Skip to content

fix(config): enable Modal artifact capture - #372

Merged
rapids-bot[bot] merged 3 commits into
NVIDIA-AI-Blueprints:release/2.2from
KyleZheng1284:fix/modal-artifact-capture-config
Jul 21, 2026
Merged

fix(config): enable Modal artifact capture#372
rapids-bot[bot] merged 3 commits into
NVIDIA-AI-Blueprints:release/2.2from
KyleZheng1284:fix/modal-artifact-capture-config

Conversation

@KyleZheng1284

@KyleZheng1284 KyleZheng1284 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Overview

Enable bounded artifact capture in the shipped Modal-backed domain-routing-and-skills profile so async jobs can persist supported CSV and chart outputs. Add a Pydantic-backed reference-profile regression test and document the required async job database plus production S3-compatible artifact storage settings.

This PR changes configuration, documentation, and profile validation only. It makes no agent, API, or sandbox-provider behavior changes.

DCO sign-off for the squash commit

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

Validation

  • .venv/bin/pytest -q tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py — 38 passed
  • .venv/bin/ruff check tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • .venv/bin/ruff format --check tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
  • .venv/bin/nat validate --config_file configs/config_domain_routing_and_skills.yml
  • .venv/bin/sphinx-build -W --keep-going -b html docs/source /tmp/aiq-pr1-docs
  • Pre-commit hooks passed on the signed commit, including YAML, secret detection, Markdown links, and conflict checks.
  • 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 configs/config_domain_routing_and_skills.yml, then the profile assertion in tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py and the storage requirements in docs/source/examples/skills-sandbox/index.md.

Related Issues

  • Relates to artifact QA cases 26.07_ART_001, 26.07_ART_002, and 26.07_SANDBOX_002.

Summary by CodeRabbit

  • New Features
    • Enabled bounded, durable capture of supported sandbox artifacts (charts/data files, notebooks, and PDFs) with a maximum file size and an allowed file-type allowlist.
  • Documentation
    • Updated the skills-sandbox example to explain durable artifact capture, supported storage options, and persistence/cancellation behavior when job-scoped storage isn’t available.
  • Tests
    • Added configuration/runtime validation to ensure the deep research sandbox enables bounded artifact capture when using the Modal-backed provider.
  • Chores
    • Adjusted the markdown link checker to ignore https://exa.ai/ URLs.

Signed-off-by: Kyle Zheng <kyzheng@nvidia.com>
@KyleZheng1284
KyleZheng1284 requested a review from a team July 20, 2026 23:44
@coderabbitai

coderabbitai Bot commented Jul 20, 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: 4ab6131c-9c4a-435b-bd92-2d7c74683db7

📥 Commits

Reviewing files that changed from the base of the PR and between b5db33e and 5648d90.

📒 Files selected for processing (1)
  • ci/markdown-link-check-config.json
📜 Recent review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Lint and Hooks
  • GitHub Check: Script Validation
  • GitHub Check: Pytest and Coverage
🧰 Additional context used
📓 Path-based instructions (1)
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}: Review automation and packaging changes for least-privilege permissions, pinned versions where appropriate,
copy-pr-bot pull-request/ branch behavior, reproducible uv/npm setup, secret handling, and consistency with
the documented validation matrix.

Files:

  • ci/markdown-link-check-config.json
🔇 Additional comments (1)
ci/markdown-link-check-config.json (1)

24-26: LGTM!


Walkthrough

The Modal deep research sandbox now enables bounded artifact capture with an extension allowlist. Runtime validation covers the shipped profile, the skills-sandbox documentation explains job-scoped storage and provider options, and Markdown link checking ignores the Exa homepage URL.

Changes

Durable artifact capture

Layer / File(s) Summary
Sandbox capture profile and validation
configs/config_domain_routing_and_skills.yml, tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
The Modal profile enables artifact capture with a 50 MB limit and an exact extension allowlist; the runtime test validates these settings.
Capture configuration documentation
docs/source/examples/skills-sandbox/index.md
The example documents the enabled capture block, job-scoped database dependency, SQL BLOB and S3-compatible storage options, and cancellation or nat run behavior.

Markdown link checking

Layer / File(s) Summary
Exa link check exclusion
ci/markdown-link-check-config.json
The Markdown link checker ignores the exact https://exa.ai/ homepage URL pattern.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • NVIDIA-AI-Blueprints/aiq#284: Modifies the DeepAgents YAML wiring around deep_research_sandbox, which this change extends with artifact capture settings.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits, uses a valid type/scope, and accurately summarizes the config change.
Description check ✅ Passed The description matches the template with overview, DCO sign-off, validation, review start, and related issues sections filled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM once pipeline passes

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

Copy link
Copy Markdown
Member

/merge

@rapids-bot
rapids-bot Bot merged commit 1208b72 into NVIDIA-AI-Blueprints:release/2.2 Jul 21, 2026
11 checks passed
rapids-bot Bot pushed a commit that referenced this pull request Jul 22, 2026
#### Overview

Deep-research currently accepts any non-empty `/shared/output.md` as the final report, including stale planner/orchestrator content from the same state. This prerequisite establishes a small writer-owned commit boundary before the broader convergence/artifact work in #373.

- Create one run-local `FinalReportCommitTracker` per `DeepResearcherAgent.run()`.
- Deny non-writer `write_file`/`edit_file` mutations of `/shared/output.md` and its route-local `/output.md` state alias with `final_report_writer_only`.
- Upsert writer `write_file` calls through the existing backend, refresh the exact UTF-8 SHA-256 after successful edits, and sanitize backend failures as `writer_output_commit_failed`.
- Require a successful writer mutation, non-empty current content, and an exact digest match before writer completion or final extraction.
- Preserve the existing one-turn correction, then fail closed with `writer_output_not_committed`.
- Remove production inline-orchestrator report salvage.
- Document that the proof is run-local and byte-exact; it is not persistent across restart and does not claim cross-provider filesystem atomicity.

This changes no API fields, configuration schema, database schema, deployment behavior, or sandbox-provider implementation.

After this prerequisite merges, #373 can rebase onto `release/2.2` and use its validated ResearchNotes fallback when no committed writer report exists.

#### DCO sign-off for the squash commit

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

#### Validation

- [x] `uv run ruff check .` — passed
- [x] `uv run ruff format --check .` — passed (372 files)
- [x] Focused deep-research/job-runner regressions — 265 passed
- [x] `uv run pytest` — 1,836 passed, 13 skipped
- [x] `pre-commit run --all-files` — all 13 hooks passed, including secrets, lockfiles, links, and notebook output
- [x] `cd docs && make html` — passed
- [x] Live Modal smoke — `deep_researcher` reached success with a non-empty 12,351-byte report
- [x] Live OpenShell 0.0.80 local-demo smoke — strict readiness passed; job reached success with a non-empty 7,360-byte report; attestation and cleanup events were recorded; no owned sandbox remained
- [x] I added or updated tests for behavior changes.
- [x] I updated documentation for contributor-facing architecture behavior.
- [x] I confirmed this PR does not include secrets, credentials, local configs, generated policy files, or internal-only data.
- [x] I certify this contribution under the Developer Certificate of Origin (DCO) and signed the commit with `git commit -s`.
- [x] I replaced the DCO sign-off placeholder with my GitHub commit identity and kept the required angle brackets.

#### Where should reviewers start?

1. `FinalReportCommitTracker`, `FinalReportOwnershipGuardMiddleware`, and `FinalReportCommitMiddleware` in `custom_middleware.py`.
2. Per-run tracker construction/extraction in `agent.py` and role-specific wiring in `factory.py`.
3. The routed `StateBackend`/`CompositeBackend` stale-planner overwrite regression in `test_custom_middleware.py`.

#### Related Issues

- Prerequisite for #373.
- Independent of #372; no artifact-capture configuration is included here.



## Summary by CodeRabbit

- **Bug Fixes**
  - Final research reports are now accepted only after the writer commits `/shared/output.md` (or the supported backend alias) during the current run.
  - Commit verification is digest-based, rejecting stale/modified/missing/whitespace-only output and detecting any post-write tampering.
  - Only the designated writer can create/update the final report artifact; completion is blocked until the verified commit occurs.
  - Removed inline fallback/salvage behavior—if the commit proof isn’t present, runs fail with `writer_output_not_committed`.
- **Documentation**
  - Updated deep-research architecture docs to describe the stricter writer/output commit contract, ownership guardrails, and failure-closed handoffs.
- **Tests**
  - Expanded coverage for digest-verified commit tracking, writer-only ownership enforcement, and updated failure reason/validation scenarios.

Authors:
  - Kyle Zheng (https://github.com/KyleZheng1284)
  - Ajay Thorve (https://github.com/AjayThorve)

Approvers:
  - Ajay Thorve (https://github.com/AjayThorve)

URL: #375
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants