Skip to content

Add trace-based behavioral tests with Monocle Test Tools - #328

Closed
imohammedansari wants to merge 1 commit into
NVIDIA-AI-Blueprints:developfrom
imohammedansari:monocle-test-tools
Closed

imohammedansari wants to merge 1 commit into
NVIDIA-AI-Blueprints:developfrom
imohammedansari:monocle-test-tools

Conversation

@imohammedansari

@imohammedansari imohammedansari commented Jul 9, 2026

Copy link
Copy Markdown

Summary

Adds a behavioral test suite that asserts against the AI-Q research agent's Monocle execution traces: which agent ran, which tools it called, what it returned, and its duration. Additive only, under tests/monocle/, with no app-code changes.

Why

The existing suite (100+ files under tests/) is thorough at the unit layer but never runs the assembled agent to check what a real run actually did. This adds that behavioral coverage, so if a later prompt, tool, or route change alters routing, tool calls, or latency, a test catches it.

How it works

It uses Monocle Test Tools. The offline tests load a recorded trace from file with with_trace_source("file", trace_path=...), which is fast, needs no keys, and is deterministic. They then assert with the fluent API: called_agent, called_tool, contains_input / contains_output, under_duration. The live test drives the real NAT workflow (via configs/config_openai_cli.yml, with an auto-approving HITL callback so a clarification or plan-approval interrupt does not block) and asserts on structure and budget only.

The point of loading from file is that the same assertions run in both modes. You pin a check against a recorded trace while iterating (fast, no keys, deterministic), then run the identical check against a live run for real regression coverage.

NAT traces carry no token metadata (inference spans record only finish reasons), so budgets are duration-based. The live test is opt-in (RUN_LIVE_NVIDIAAIQ=1) and runs one at a time, since NAT binds its asyncio singletons to the first event loop.

Changes (all under tests/monocle/)

  • test_nvidiaaiq.py: 2 offline file-loaded tests (a capabilities intro answered directly; an NVIDIA stock-price lookup via web_search_tool), plus 1 live test (stock-price lookup, opt-in via RUN_LIVE_NVIDIAAIQ=1).
  • conftest.py: Monocle setup, .env loading, run_nvidiaaiq() (auto-approve HITL).
  • traces/: 2 recorded traces.
  • configs/config_openai_cli.yml, requirements.txt, README.md.

Summary by CodeRabbit

  • New Features

    • Added a ready-to-use OpenAI CLI configuration with web search, research workflows, citation verification, and configurable checkpoints.
    • Configured shallow vs. deep research behavior with tailored escalation, clarification, and planning.
  • Documentation

    • Added a Monocle-based trace testing guide, including offline replay and opt-in live run instructions.
  • Tests

    • Added Monocle trace-based behavioral tests for capability queries and stock-price research, validating tool usage and workflow duration budgets (with optional live verification).
  • Chores

    • Updated ignore rules to prevent Monocle trace artifacts from being tracked.

PS: if Monocle looks useful, a ⭐ helps the project (https://github.com/monocle2ai/monocle). The instrumentation that emits these traces is the companion PR (#327).

@copy-pr-bot

copy-pr-bot Bot commented Jul 9, 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 9, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds a default OpenAI CLI research workflow and a Monocle test suite with offline trace replay, opt-in live execution, recorded traces, dependencies, documentation, and generated-artifact ignore rules.

Changes

OpenAI CLI and Monocle testing

Layer / File(s) Summary
OpenAI CLI workflow configuration
configs/config_openai_cli.yml
Defines telemetry, two OpenAI LLMs, web-search data sources, agent tool inheritance and exclusions, workflow escalation, clarifiers, and checkpoint storage.
Monocle harness and behavioral assertions
tests/monocle/conftest.py, tests/monocle/test_nvidiaaiq.py
Initializes tracing, provides a live workflow runner with automatic approvals, and tests capability responses, stock lookup behavior, tool calls, outputs, and duration budgets.
Trace fixtures and test support
tests/monocle/traces/*, tests/monocle/README.md, tests/monocle/requirements.txt, .gitignore
Adds recorded workflow traces, test execution documentation and dependencies, and ignores .monocle/ artifacts.

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

Sequence Diagram(s)

sequenceDiagram
  participant Test as test_nvidiaaiq
  participant Runner as run_nvidiaaiq
  participant Workflow as chat_deepresearcher_agent
  participant Search as web_search_tool
  participant Assertions as Monocle trace assertions
  Test->>Runner: Run stock-price query
  Runner->>Workflow: Execute configured workflow
  Workflow->>Search: Search rewritten stock query
  Search-->>Workflow: Return market documents
  Workflow-->>Runner: Return cited response
  Runner-->>Test: Return workflow result
  Test->>Assertions: Validate agent, tool, output, and duration
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Title check ❌ Error The title is clear, but it does not use the required Conventional Commits format with a lowercase type prefix. Rename it to a Conventional Commit like test: add trace-based behavioral tests with Monocle Test Tools.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description check ✅ Passed The description covers the change, motivation, implementation, and touched files, and is detailed enough despite missing the exact template headings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

Caution

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

⚠️ Outside diff range comments (1)
tests/monocle/requirements.txt (1)

1-6: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Pin tests/monocle/requirements.txt
monocle_test_tools and python-dotenv are floating here. Pin them so the Monocle test environment stays reproducible; monocle_test_tools currently resolves a broad transitive set (gitpython==3.1.45, sentence-transformers==3.3.0, transformers>=4.0.0, etc.), so leaving it unpinned can drift into different or vulnerable releases over time.

🤖 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/monocle/requirements.txt` around lines 1 - 6, Pin both dependencies in
tests/monocle/requirements.txt by assigning explicit, reviewed versions to
monocle_test_tools and python-dotenv, using compatible versions for the existing
Monocle test suite and its transitive requirements.

Source: Linters/SAST tools

🤖 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
`@tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json`:
- Line 18: Remove contributor-specific absolute filesystem paths from every
span_source entry in the referenced trace fixture, including all listed
occurrences. Replace the local path prefix with a neutral placeholder while
preserving the package/module and location suffix needed by the fixture.

---

Outside diff comments:
In `@tests/monocle/requirements.txt`:
- Around line 1-6: Pin both dependencies in tests/monocle/requirements.txt by
assigning explicit, reviewed versions to monocle_test_tools and python-dotenv,
using compatible versions for the existing Monocle test suite and its transitive
requirements.
🪄 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: d5cec655-dfc1-4161-9b44-726ade818001

📥 Commits

Reviewing files that changed from the base of the PR and between f0e0fbc and efd4bb3.

📒 Files selected for processing (8)
  • .gitignore
  • configs/config_openai_cli.yml
  • tests/monocle/README.md
  • tests/monocle/conftest.py
  • tests/monocle/requirements.txt
  • tests/monocle/test_nvidiaaiq.py
  • tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json
  • tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**

⚙️ 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/monocle/requirements.txt
  • tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json
  • tests/monocle/README.md
  • tests/monocle/conftest.py
  • tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json
  • configs/config_openai_cli.yml
  • tests/monocle/test_nvidiaaiq.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/monocle/conftest.py
  • tests/monocle/test_nvidiaaiq.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/monocle/conftest.py
  • tests/monocle/test_nvidiaaiq.py
{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_openai_cli.yml
🪛 OSV Scanner (2.4.0)
tests/monocle/requirements.txt

[HIGH] 1-1: gitpython 3.1.45: GitPython reference APIs has a path traversal vulnerability that allows arbitrary file write and delete outside the repository

(GHSA-7545-fcxq-7j24)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer() section parameter bypasses CVE-2026-42215 patch, enabling RCE via core.hooksPath

(GHSA-mv93-w799-cj2w)


[HIGH] 1-1: gitpython 3.1.45: GitPython has Command Injection via Git options bypass

(GHSA-rpm5-65cw-6hj4)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer().set_value() enables RCE via core.hooksPath

(GHSA-v87r-6q3f-2j67)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Unsafe option check validates multi_options before shlex.split transformation

(GHSA-x2qx-6953-8485)


[HIGH] 1-1: torch 2.9.1: undefined

(PYSEC-2026-139)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.lstm_cell function

(GHSA-qfhq-4f3w-5fph)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.jit.script function

(GHSA-rrmf-rvhw-rf47)


[HIGH] 1-1: transformers 4.57.6: undefined

(PYSEC-2025-217)


[HIGH] 1-1: transformers 4.57.6: HuggingFace transformers vulnerable to remote code execution

(GHSA-29pf-2h5f-8g72)


[HIGH] 1-1: transformers 4.57.6: HuggingFace Transformers allows for arbitrary code execution in the Trainer class

(GHSA-69w3-r845-3855)

🔇 Additional comments (8)
tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json (1)

18-18: 🔒 Security & Privacy | ⚡ Quick win

Same local-path leak as the sibling trace fixture.

Same span_source local-path leak (contributor username + directory layout) as flagged in monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_...json. Apply the same redaction here.

Also applies to: 52-52, 113-113, 168-168, 221-221

configs/config_openai_cli.yml (1)

1-130: LGTM!

tests/monocle/conftest.py (1)

7-57: LGTM! The double-import guard and lazy NAT imports are sensible for a mixed offline/live test scaffold.

tests/monocle/test_nvidiaaiq.py (3)

27-30: 🩺 Stability & Availability | ⚖️ Poor tradeoff

Generic conftest module name risk with manual sys.path import.

Using a bare import conftest after sys.path.insert works today because this is the only file doing it, but it's fragile: Python caches modules by name in sys.modules, so if any other test directory in this repo (or added later) performs the same "insert own dir + import conftest" pattern, whichever import runs first wins and later imports silently reuse the wrong module. The double-instrumentation guard in conftest.py (Lines 22-25) already anticipates a second import of this file, but a name collision with an unrelated conftest.py elsewhere is a different failure mode it doesn't protect against.

Consider importing via importlib.util.spec_from_file_location with a unique module name, or extracting TRACES/run_nvidiaaiq into a uniquely-named helper module instead of relying on pytest's own conftest.py discovery file.


42-91: LGTM! Offline assertions match the recorded trace fixtures (durations, tool calls, outputs all line up).


93-104: 🎯 Functional Correctness

Monocle fixture/API usage matches the suite.

			> Likely an incorrect or invalid review comment.
tests/monocle/README.md (1)

1-74: LGTM!

.gitignore (1)

43-45: LGTM!

Trace-based tests under tests/monocle/ asserting against the agent's Monocle execution traces (agent, tools, output, duration budget).

Signed-off-by: Mohammed Ansari <mohammed.ansari@okahu.ai>

@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: 5

🤖 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 `@tests/monocle/conftest.py`:
- Around line 49-52: Remove the broad exception suppression around
ContextState.get().conversation_id.set(...) in the fixture setup; allow failures
to propagate so the fixture fails visibly, or explicitly log the exception
before handling it.

In `@tests/monocle/README.md`:
- Around line 45-49: Update the live-test documentation near the
`RUN_LIVE_NVIDIAAIQ` instructions to require `EXA_API_KEY` only, matching the
active `exa_web_search` configuration in `configs/config_openai_cli.yml`; remove
`SERPER_API_KEY` as an alternative, or instead change the workflow and maintain
documentation parity for the configured search provider.

In `@tests/monocle/requirements.txt`:
- Around line 1-5: Pin monocle_test_tools and its monocle_apptrace dependency in
tests/monocle/requirements.txt, either with compatible explicit versions or a
constraints file referenced by the requirements. Preserve the existing pytest
and environment-loading dependencies while ensuring repeated installs use
versions compatible with the recorded trace fixtures.

In `@tests/monocle/test_nvidiaaiq.py`:
- Around line 87-90: The _LIVE skip marker currently checks only
RUN_LIVE_NVIDIAAIQ; update it to also skip unless OPENAI_API_KEY and the
configured EXA_API_KEY environment variables are present, without logging or
exposing secret values. Do not use SERPER_API_KEY as a substitute, and ensure
missing credentials result in a graceful skip rather than workflow or
tool-execution failure.
- Around line 101-103: The output assertion in the NVIDIA test is too broad and
can accept error messages. Update the assertion near
monocle_trace_asserter.called_agent("LangGraph") to require stable success
indicators, including a citation section and a currency/amount pattern, while
leaving the exact market value unconstrained; retain the existing agent and tool
assertions.
🪄 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: 2ff52581-21f8-4425-8cb4-d60f27dcd2a4

📥 Commits

Reviewing files that changed from the base of the PR and between efd4bb3 and 207f4b9.

📒 Files selected for processing (8)
  • .gitignore
  • configs/config_openai_cli.yml
  • tests/monocle/README.md
  • tests/monocle/conftest.py
  • tests/monocle/requirements.txt
  • tests/monocle/test_nvidiaaiq.py
  • tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json
  • tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: CodeRabbit / Review
🧰 Additional context used
📓 Path-based instructions (4)
**

⚙️ 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/monocle/requirements.txt
  • tests/monocle/README.md
  • configs/config_openai_cli.yml
  • tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json
  • tests/monocle/conftest.py
  • tests/monocle/test_nvidiaaiq.py
  • tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json
{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_openai_cli.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/monocle/conftest.py
  • tests/monocle/test_nvidiaaiq.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/monocle/conftest.py
  • tests/monocle/test_nvidiaaiq.py
🪛 OSV Scanner (2.4.0)
tests/monocle/requirements.txt

[HIGH] 1-1: gitpython 3.1.45: GitPython reference APIs has a path traversal vulnerability that allows arbitrary file write and delete outside the repository

(GHSA-7545-fcxq-7j24)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer() section parameter bypasses CVE-2026-42215 patch, enabling RCE via core.hooksPath

(GHSA-mv93-w799-cj2w)


[HIGH] 1-1: gitpython 3.1.45: GitPython has Command Injection via Git options bypass

(GHSA-rpm5-65cw-6hj4)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer().set_value() enables RCE via core.hooksPath

(GHSA-v87r-6q3f-2j67)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Unsafe option check validates multi_options before shlex.split transformation

(GHSA-x2qx-6953-8485)


[HIGH] 1-1: torch 2.9.1: undefined

(PYSEC-2026-139)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.lstm_cell function

(GHSA-qfhq-4f3w-5fph)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.jit.script function

(GHSA-rrmf-rvhw-rf47)


[HIGH] 1-1: transformers 4.57.6: undefined

(PYSEC-2025-217)


[HIGH] 1-1: transformers 4.57.6: HuggingFace transformers vulnerable to remote code execution

(GHSA-29pf-2h5f-8g72)


[HIGH] 1-1: transformers 4.57.6: HuggingFace Transformers allows for arbitrary code execution in the Trainer class

(GHSA-69w3-r845-3855)

🔇 Additional comments (8)
configs/config_openai_cli.yml (2)

68-76: 🩺 Stability & Availability

Verify graceful behavior when EXA_API_KEY is absent.

Both Exa tools are enabled by default, while the supplied validation contract only checks LLM keys. If the tool does not already stub or skip without EXA_API_KEY, a normal CLI run can fail at tool invocation. Add an explicit guard/fallback or a test covering the missing-key path.

As per coding guidelines, missing-secret paths must degrade gracefully (stub/skip), not crash. As per path instructions, config changes must be reviewed for secret separation and safe defaults.

Sources: Coding guidelines, Path instructions


1-67: LGTM!

Also applies to: 77-130

tests/monocle/conftest.py (1)

1-48: LGTM!

Also applies to: 53-58

tests/monocle/test_nvidiaaiq.py (1)

1-86: LGTM!

Also applies to: 91-100, 104-110

tests/monocle/traces/monocle_trace_nvidia-aiq_e2961458302a780a27f91a0d86b290dd_2026-07-09_13.25.14.json (1)

1-547: LGTM!

tests/monocle/README.md (1)

1-44: LGTM!

Also applies to: 50-74

tests/monocle/traces/monocle_trace_nvidia-aiq_4a94876861e3ade549dc74fb785e94d9_2026-07-09_13.17.46.json (1)

1-241: LGTM!

.gitignore (1)

43-45: 📐 Maintainability & Code Quality | ⚡ Quick win

Also isolate or ignore workflow checkpoint artifacts.

The documented live command uses checkpoint_db: ./checkpoints.db, so it may leave checkpoints.db and SQLite sidecar files in the checkout. This block ignores only .monocle/; use a temporary checkpoint path for live tests or add an ignore pattern such as checkpoints.db*.

As per path instructions, config changes must be reviewed for safe local-vs-production behavior.

Source: Path instructions

Comment thread tests/monocle/conftest.py
Comment on lines +49 to +52
try:
ContextState.get().conversation_id.set(str(uuid.uuid4()))
except Exception:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File context =="
sed -n '1,140p' tests/monocle/conftest.py

echo
echo "== Search for ContextState usages =="
rg -n "ContextState|get\(\)\.conversation_id|conversation_id\.set|conversation_id" tests src sources -g '!**/.venv/**' -g '!**/node_modules/**' || true

echo
echo "== Search for monocle fixtures/tests =="
rg -n "monocle|run_nvidiaaiq|conversation_id" tests -g '!**/.venv/**' || true

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 23860


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Monocle README =="
sed -n '1,140p' tests/monocle/README.md

echo
echo "== Monocle test file =="
sed -n '1,180p' tests/monocle/test_nvidiaaiq.py

echo
echo "== Search for conversation-id docs in repo =="
rg -n "conversation-id|conversation_id|ContextState|checkpoint|state leakage|thread ID" tests/monocle docs/source src sources -g '!**/.venv/**' -g '!**/node_modules/**' || true

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 20851


🌐 Web query:

NeMo Agent Toolkit ContextState.get optional-context exception conversation_id set documented failure mode

💡 Result:

In the NVIDIA NeMo Agent Toolkit, ContextState is implemented as a singleton that manages context variables using contextvars [1][2]. The method ContextState.get() is used to retrieve the global ContextState instance [3][2][4]. There is no documented "failure mode" specifically for ContextState.get() regarding an "optional-context" exception or conversation_id. Based on the toolkit's architecture: 1. Context Management: ContextState provides thread-local or asynchronous-task-local storage for metadata such as conversation_id, user_id, and workflow_run_id [5][3][1]. 2. Property Access: The conversation_id property typically calls self._context_state.conversation_id.get() [5]. If the conversation_id has not been set in the current execution context, contextvars.ContextVar.get() will return its default value (which is None unless otherwise specified) [5][1]. It does not inherently raise an exception [5]. 3. Error Handling: While there are no exceptions specifically tied to accessing an unset conversation_id, the toolkit has implemented rigorous error propagation patterns in other areas (such as agent registration and runner result logging) to avoid "swallowing" exceptions [6]. If you are encountering an unexpected failure, it may be related to how downstream logic expects a non-null conversation_id or how ContextState is initialized within your specific runtime environment (e.g., inside an async with session(...) block) [3][1]. If you are experiencing an error, verify that the conversation_id has been explicitly set using context_state.conversation_id.set("your-id") within your session scope [3][1]. If you are working with custom components, ensure your usage conforms to the standard ContextState access patterns found in the nat.builder.context module [7][5][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Live workflow config =="
sed -n '1,220p' configs/config_openai_cli.yml

echo
echo "== Search for checkpoint / conversation wiring in configs =="
rg -n "checkpoint|conversation-id|conversation_id|thread_id|ContextState" configs src tests -g '!**/.venv/**' -g '!**/node_modules/**' || true

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 21651


Don't silence context setup failures here. If ContextState.get().conversation_id.set(...) raises, let the fixture fail or log it explicitly so the live trace doesn't silently lose its per-run conversation 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 `@tests/monocle/conftest.py` around lines 49 - 52, Remove the broad exception
suppression around ContextState.get().conversation_id.set(...) in the fixture
setup; allow failures to propagate so the fixture fails visibly, or explicitly
log the exception before handling it.

Comment thread tests/monocle/README.md
Comment on lines +45 to +49
The live test is opt-in (`RUN_LIVE_NVIDIAAIQ=1`) and skipped by default.
NAT binds its async singletons to the first event loop, so only one in-process
live run works per process, and NAT leaves non-daemon threads that keep the
interpreter from exiting cleanly. So run the live test in its own process, with
keys in `deploy/.env` (`OPENAI_API_KEY` plus a search key, `EXA_API_KEY`/`SERPER_API_KEY`):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the key required by the configured live workflow.

configs/config_openai_cli.yml enables _type: exa_web_search; SERPER_API_KEY is only associated with the commented paper-search configuration. Listing it as an alternative can lead users to run the live test without the required Exa credential. Document EXA_API_KEY only, or change the workflow to use Serper.

As per path instructions, config changes must preserve documentation parity.

🤖 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/monocle/README.md` around lines 45 - 49, Update the live-test
documentation near the `RUN_LIVE_NVIDIAAIQ` instructions to require
`EXA_API_KEY` only, matching the active `exa_web_search` configuration in
`configs/config_openai_cli.yml`; remove `SERPER_API_KEY` as an alternative, or
instead change the workflow and maintain documentation parity for the configured
search provider.

Source: Path instructions

Comment on lines +1 to +5
# Installing monocle_test_tools pulls in everything this suite needs
# (pytest, pytest-asyncio, and monocle_apptrace come transitively).
monocle_test_tools
# Auto-loads the repo deploy/.env for the live tests.
python-dotenv

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== tests/monocle/requirements.txt ==\n'
cat -n tests/monocle/requirements.txt

printf '\n== Nearby monocle files ==\n'
git ls-files 'tests/monocle/*' | sed 's#^`#-` #'

printf '\n== Search for monocle_test_tools / monocle_apptrace / python-dotenv / constraints ==\n'
rg -n --hidden --glob '!**/.git/**' \
  'monocle_test_tools|monocle_apptrace|python-dotenv|requirements\.txt|constraints|lockfile|uv\.lock|poetry\.lock|pip-tools|pip compile' \
  tests sources src docs configs .agents skills frontends deploy .

printf '\n== Dependency files that may constrain tests/monocle ==\n'
fd -H -a 'requirements.*|uv\.lock|pyproject\.toml|constraints.*|lock.*' tests . | sed 's#^`#-` #'

printf '\n== tests/monocle tree ==\n'
find tests/monocle -maxdepth 2 -type f | sort | sed 's#^`#-` #'

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 29858


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== tests/monocle/README.md ==\n'
cat -n tests/monocle/README.md

printf '\n== tests/monocle/conftest.py ==\n'
cat -n tests/monocle/conftest.py

printf '\n== tests/monocle/test_nvidiaaiq.py ==\n'
cat -n tests/monocle/test_nvidiaaiq.py

printf '\n== monocle-related entries in uv.lock ==\n'
python3 - <<'PY'
from pathlib import Path
text = Path("uv.lock").read_text()
for needle in ["monocle_test_tools", "monocle_apptrace", "python-dotenv"]:
    print(f"\n-- {needle} --")
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            print(f"{i}: {line}")
PY

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 13807


Pin the Monocle test deps. requirements.txt is installed directly with pip install -r, so monocle_test_tools can drift and pull a different monocle_apptrace, breaking the recorded trace fixtures. Add version pins or a constraints file for this suite.

🧰 Tools
🪛 OSV Scanner (2.4.0)

[HIGH] 1-1: gitpython 3.1.45: GitPython reference APIs has a path traversal vulnerability that allows arbitrary file write and delete outside the repository

(GHSA-7545-fcxq-7j24)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer() section parameter bypasses CVE-2026-42215 patch, enabling RCE via core.hooksPath

(GHSA-mv93-w799-cj2w)


[HIGH] 1-1: gitpython 3.1.45: GitPython has Command Injection via Git options bypass

(GHSA-rpm5-65cw-6hj4)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Newline injection in config_writer().set_value() enables RCE via core.hooksPath

(GHSA-v87r-6q3f-2j67)


[HIGH] 1-1: gitpython 3.1.45: GitPython: Unsafe option check validates multi_options before shlex.split transformation

(GHSA-x2qx-6953-8485)


[HIGH] 1-1: torch 2.9.1: undefined

(PYSEC-2026-139)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.lstm_cell function

(GHSA-qfhq-4f3w-5fph)


[HIGH] 1-1: torch 2.9.1: PyTorch is vulnerable to memory corruption through its torch.jit.script function

(GHSA-rrmf-rvhw-rf47)


[HIGH] 1-1: transformers 4.57.6: undefined

(PYSEC-2025-217)


[HIGH] 1-1: transformers 4.57.6: HuggingFace transformers vulnerable to remote code execution

(GHSA-29pf-2h5f-8g72)


[HIGH] 1-1: transformers 4.57.6: HuggingFace Transformers allows for arbitrary code execution in the Trainer class

(GHSA-69w3-r845-3855)

🤖 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/monocle/requirements.txt` around lines 1 - 5, Pin monocle_test_tools
and its monocle_apptrace dependency in tests/monocle/requirements.txt, either
with compatible explicit versions or a constraints file referenced by the
requirements. Preserve the existing pytest and environment-loading dependencies
while ensuring repeated installs use versions compatible with the recorded trace
fixtures.

Source: Linters/SAST tools

Comment on lines +87 to +90
_LIVE = pytest.mark.skipif(
os.environ.get("RUN_LIVE_NVIDIAAIQ") != "1",
reason="opt-in live run (set RUN_LIVE_NVIDIAAIQ=1; run one live test per process -- see note above)",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Skip the live test when required credentials are unavailable.

The marker checks only RUN_LIVE_NVIDIAAIQ. Enabling it without OPENAI_API_KEY or the configured EXA_API_KEY can make workflow loading or tool execution fail instead of skipping safely. Gate the test on those environment variables without exposing their values; SERPER_API_KEY is not a substitute for this Exa-backed configuration.

As per coding guidelines, missing-secret paths must degrade gracefully (stub/skip), not crash.

🤖 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/monocle/test_nvidiaaiq.py` around lines 87 - 90, The _LIVE skip marker
currently checks only RUN_LIVE_NVIDIAAIQ; update it to also skip unless
OPENAI_API_KEY and the configured EXA_API_KEY environment variables are present,
without logging or exposing secret values. Do not use SERPER_API_KEY as a
substitute, and ensure missing credentials result in a graceful skip rather than
workflow or tool-execution failure.

Source: Coding guidelines

Comment on lines +101 to +103
monocle_trace_asserter.called_agent("LangGraph")
monocle_trace_asserter.contains_any_output("NVIDIA", "NVDA", "stock", "price")
monocle_trace_asserter.called_tool("web_search_tool", "LangGraph")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the live assertion reject error responses.

contains_any_output("NVIDIA", "NVDA", "stock", "price") can pass for an error such as “I couldn’t retrieve the stock price.” Assert stable success markers, such as a citation section plus a currency/amount pattern, while keeping the exact market value unconstrained.

🤖 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/monocle/test_nvidiaaiq.py` around lines 101 - 103, The output assertion
in the NVIDIA test is too broad and can accept error messages. Update the
assertion near monocle_trace_asserter.called_agent("LangGraph") to require
stable success indicators, including a citation section and a currency/amount
pattern, while leaving the exact market value unconstrained; retain the existing
agent and tool assertions.

@tanleach

Copy link
Copy Markdown
Collaborator

Thanks for the companion testing proposal. The goal of catching agent-behavior regressions from structured traces is valuable, but AIQ’s trace contract has changed since this was opened. develop now uses NeMo Relay, and its tests intentionally assert semantic AIQ workflow and agent scopes rather than the generic LangGraph identity used by these Monocle fixtures.

The two offline tests here also replay fixed trace files, so they validate those fixtures rather than execute the current application. Only the opt-in live test exercises AIQ, and the suite is not integrated into the repository’s locked test environment or CI.

If we add more assembled-agent behavioral coverage, it should be Relay-native: ideally a deterministic current-workflow run that generates ephemeral ATOF/OTEL and asserts semantic agent and tool behavior without adding a second instrumentation runtime. If Monocle Test Tools can consume Relay ATOF or OTLP/OpenInference directly, please point us to that support and we can evaluate a consumer-only approach.

Given the current architecture, we’re going to close this PR alongside #327 as superseded. Thank you again for the contribution and for demonstrating the testing idea.

@tanleach tanleach closed this Aug 25, 2026
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.

2 participants