Skip to content

refactor: update citation verification handling in DeepResearcherAgent - #237

Closed
rkarmaka wants to merge 19 commits into
NVIDIA-AI-Blueprints:developfrom
rkarmaka:fix/issue-235-empty-source-registry
Closed

refactor: update citation verification handling in DeepResearcherAgent#237
rkarmaka wants to merge 19 commits into
NVIDIA-AI-Blueprints:developfrom
rkarmaka:fix/issue-235-empty-source-registry

Conversation

@rkarmaka

@rkarmaka rkarmaka commented May 13, 2026

Copy link
Copy Markdown
  • Removed the raising of EmptySourceRegistryError when no sources are available during deep research.
  • Added logging for cases where reports are generated without captured sources, indicating whether tools were unavailable or if the model answered without using search results.
  • Introduced a new citation_verification_status field in DeepResearchAgentState to track unverified reports, including the reason and available tool count.
  • Updated tests to ensure correct behavior when the source registry is empty and when sources are captured.

Summary by CodeRabbit

  • New Features
    • Deep-research job report endpoints now expose citation_verification_status and consistently surface the related warning in returned report text.
    • Report-context, report-edit, and report-rewrite flows now propagate citation-verification disposition through to the final output.
  • Bug Fixes
    • Deep research no longer fails when citation verification is enabled but no sources or tools are available; reports are returned with an unverified disposition.
    • Inline chat-researcher reporting now applies the same warning and disposition handling.
  • Tests
    • Expanded unit tests for warning prefixing, API field exposure, status sanitization, and verified/unverified/disabled cases.

@rkarmaka

Copy link
Copy Markdown
Author

@cdgamarose-nv Solving issue #235

@greptile-apps

greptile-apps Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR refactors how DeepResearcherAgent handles an empty source registry: rather than raising EmptySourceRegistryError and losing the report, it now returns the report with a citation_verification_status field set to "unverified", and logs the condition at error or warning level. The chat_researcher wiring to surface that flag as a user-facing message is explicitly deferred (old except block left as commented-out reference).

  • deep_researcher/agent.py: Replaced the raise EmptySourceRegistryError path with conditional logging and mutation of the result dict to set citation_verification_status before model_validate.
  • deep_researcher/models/state.py: Added citation_verification_status: dict[str, Any] | None = None to DeepResearchAgentState, following the existing dict[str, Any] convention for structured payload fields.
  • tests/test_agent.py: Two new regression tests cover the empty-registry (unverified status set) and populated-registry (status stays None) code paths.

Confidence Score: 4/5

The deep-researcher logic change is sound, but the chat_researcher node does not yet read citation_verification_status, so users can receive an unverified or potentially hallucinated deep-research report with no indication that source verification was skipped.

The state-model and deep-researcher changes are clean and the new tests cover the two key branches. The gap is in chat_researcher: citation_verification_status is populated by deep_researcher but never inspected when building the response returned to the caller, meaning the unverified-report UX improvement the PR is building toward is currently absent.

src/aiq_agent/agents/chat_researcher/agent.py — the citation_verification_status field on the returned DeepResearchAgentState is not yet consumed here.

Important Files Changed

Filename Overview
src/aiq_agent/agents/deep_researcher/agent.py Replaced EmptySourceRegistryError raise with log + citation_verification_status dict mutation; logic is correct for the normal case but the unverified report flows silently to the caller
src/aiq_agent/agents/chat_researcher/agent.py Old except EmptySourceRegistryError block is commented out and citation_verification_status is never read from the result, so unverified deep-research reports reach users without any indication
src/aiq_agent/agents/deep_researcher/models/state.py Added citation_verification_status field following the existing dict[str, Any]
tests/aiq_agent/agents/deep_researcher/test_agent.py Two new tests cover empty-registry and populated-registry paths; test_run_with_sources_leaves_verification_status_none relies on self.registry being returned by _get_registry() (true only when no session registry is active)

Sequence Diagram

sequenceDiagram
    participant CR as ChatResearcherAgent
    participant DR as DeepResearcherAgent
    participant SRM as SourceRegistryMiddleware
    participant CV as citation_verification

    CR->>DR: deep_research_fn(deep_state)
    DR->>DR: agent.ainvoke() [retry loop]
    DR->>SRM: _get_registry().all_sources()
    alt Sources captured
        SRM-->>DR: [source list]
        DR->>CV: verify_citations(report, registry)
        CV-->>DR: verified_report
        DR-->>CR: "DeepResearchAgentState(citation_verification_status=None)"
    else Empty source registry
        SRM-->>DR: []
        DR->>DR: validate_tool_availability()
        alt "available_count == 0"
            DR->>DR: logger.error(all tools unavailable)
        else "available_count > 0"
            DR->>DR: logger.warning(model answered without search)
        end
        DR->>DR: "result[citation_verification_status] = {status: unverified, ...}"
        DR-->>CR: "DeepResearchAgentState(citation_verification_status={status: unverified, ...})"
        Note over CR: citation_verification_status NOT checked - unverified report returned silently
    end
Loading

Reviews (2): Last reviewed commit: "refactor: update error handling in deep ..." | Re-trigger Greptile

Comment thread src/aiq_agent/agents/deep_researcher/models/state.py Outdated
@cdgamarose-nv

Copy link
Copy Markdown
Collaborator

Thank you for your contribution @rkarmaka. We will review soon

@AjayThorve

Copy link
Copy Markdown
Member

@rkarmaka can you resolve conflicts?

@AjayThorve

Copy link
Copy Markdown
Member

/ok to test 54fc182

@AjayThorve

Copy link
Copy Markdown
Member

@rkarmaka if you can fix the conflicts, we can make sure this goes into 2.2 release

@AjayThorve

Copy link
Copy Markdown
Member

/ok to test 54fc182

@rkarmaka

rkarmaka commented Jul 7, 2026

Copy link
Copy Markdown
Author

@AjayThorve Sorry I missed your earlier comment. I will go ahead and resolve the conflict. Thanks!

@copy-pr-bot

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

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Deep research now records citation-verification outcomes, propagates sanitized status through report contexts and job APIs, preserves it across report edits, and displays warnings in chat and UI reports.

Changes

Citation Verification Status Propagation

Layer / File(s) Summary
Citation verification state contract
src/aiq_agent/common/citation_verification.py, src/aiq_agent/agents/deep_researcher/models/*, src/aiq_agent/agents/chat_researcher/models/state.py
Adds structured outcomes, warning normalization, report-status fields, reducers, and package exports.
Deep research fallback and warning flow
src/aiq_agent/agents/deep_researcher/agent.py, tests/aiq_agent/agents/deep_researcher/*
Records verified, disabled, and unverified outcomes, continues when sources or tools are unavailable, and prefixes warnings on final reports.
Report rewriting and follow-up propagation
src/aiq_agent/agents/report_rewriter/*, src/aiq_agent/agents/chat_researcher/*, tests/aiq_agent/agents/{report_rewriter,chat_researcher}/*
Preserves citation status through rewritten reports, inline chat turns, report contexts, and follow-up metadata.
Job output and report API propagation
frontends/aiq_api/src/aiq_api/jobs/*, frontends/aiq_api/src/aiq_api/routes/jobs.py, tests/aiq_agent/{jobs,fastapi_extensions}/*, frontends/aiq_api/tests/*
Strips warnings from stored reports, persists normalized status, and exposes it through report responses and child-job metadata.
UI report warning presentation
frontends/ui/src/adapters/api/*, frontends/ui/src/features/chat/hooks/use-load-job-data.*
Adds report status types and applies warnings across REST report-loading paths with idempotent tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant DeepResearcherAgent
  participant JobRunner
  participant JobsAPI
  participant UIReportLoader
  DeepResearcherAgent->>JobRunner: attach citation_verification_status
  JobRunner->>JobRunner: strip warning and persist report status
  JobRunner->>JobsAPI: return report and citation status
  JobsAPI->>UIReportLoader: provide JobReportResponse
  UIReportLoader->>UIReportLoader: prepend warning when present
  UIReportLoader->>UIReportLoader: set report content
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete and does not follow the required template sections like Overview, DCO sign-off, Validation, or reviewer guidance. Rewrite the PR description using the repository template and fill in Overview, DCO sign-off, Validation checklist, Where should reviewers start?, and Related Issues.
Docstring Coverage ⚠️ Warning Docstring coverage is 64.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches Conventional Commits, is under 72 characters, and accurately summarizes the refactor.
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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 2

🤖 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 `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 333-356: `deep_research_node` is dropping
`citation_verification_status`, so chat can’t distinguish verified from
unverified deep research results. Update `chat_researcher/agent.py` in the
`self.deep_research_fn(deep_state)` flow to propagate the status from the deep
research result into the returned payload (or use it to emit a user-facing
notice when unverified), and remove the stale commented-out
`EmptySourceRegistryError` block now that that path is no longer used.

In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 314-334: The `citation_verification_status.reason` in
`deep_researcher/agent.py` is too generic and does not distinguish between the
“all tools unavailable” path and the “tools available but unused” path. Update
the logic around the `logger.error`/`logger.warning` branches so the
`result["citation_verification_status"]` payload gets a distinct
machine-readable `reason` based on `available_count` and `unavailable` (for
example, one value for unavailable tools and another for unused tools), while
keeping the rest of the status fields intact.
🪄 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: 05745aa1-39d0-413c-95ff-4a36f055237b

📥 Commits

Reviewing files that changed from the base of the PR and between d942536 and 1c1c697.

📒 Files selected for processing (4)
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.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:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.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:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🧠 Learnings (1)
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🔇 Additional comments (3)
src/aiq_agent/agents/deep_researcher/models/state.py (1)

58-76: LGTM!

tests/aiq_agent/agents/deep_researcher/test_agent.py (1)

1038-1085: LGTM!

src/aiq_agent/agents/deep_researcher/agent.py (1)

328-334: 🩺 Stability & Availability

No issue here. agent.ainvoke() is used in the default mapping-returning path, and citation_verification_status is already a field on DeepResearchAgentState.

			> Likely an incorrect or invalid review comment.

Comment thread src/aiq_agent/agents/chat_researcher/agent.py Outdated
Comment thread src/aiq_agent/agents/deep_researcher/agent.py Outdated
@rkarmaka
rkarmaka force-pushed the fix/issue-235-empty-source-registry branch from 1c1c697 to a23a4a0 Compare July 8, 2026 00:17
rkarmaka and others added 3 commits July 7, 2026 20:19
-
- Removed the raising of EmptySourceRegistryError when no sources are available during deep research.
- Added logging for cases where reports are generated without captured sources, indicating whether tools were unavailable or if the model answered without using search results.
- Introduced a new citation_verification_status field in DeepResearchAgentState to track unverified reports, including the reason and available tool count.
- Updated tests to ensure correct behavior when the source registry is empty and when sources are captured.

Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
- Removed the raising of EmptySourceRegistryError when no verifiable sources are found during deep research.
- Retained commented-out code for reference, indicating the previous error handling approach.
- Adjusted the flow to ensure reports are returned with citation verification status, preventing loss of information when sources are unavailable.

Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
Remove leftover conflict markers from the develop rebase, drop unused
imports in DeepResearcherAgent, and keep both the new unverified-status
tests and develop's writer-markdown test with the factory patch path.

Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
@rkarmaka
rkarmaka force-pushed the fix/issue-235-empty-source-registry branch from a23a4a0 to 84d08eb Compare July 8, 2026 00:20

@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

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

⚠️ Outside diff range comments (1)
src/aiq_agent/agents/deep_researcher/agent.py (1)

182-195: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

state.files fallback is lost for dict results due to operator precedence.

Line 185 parses as result.get("files", None) for the dict branch and getattr(result, "files", None) or files or {} for the non-dict branch. The or files or {} fallback only applies to the non-dict case. When result is a dict without a "files" key (or with None), files becomes None and the state.files fallback passed at line 274 is silently ignored, falling through to _salvage_inline_report instead.

🐛 Proposed fix — wrap the ternary in parentheses so the fallback applies to both branches
-        files = result.get("files", None) if isinstance(result, dict) else getattr(result, "files", None) or files or {}
+        files = (result.get("files", None) if isinstance(result, dict) else getattr(result, "files", None)) or files or {}
🤖 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 `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 182 - 195, The
fallback to state.files is only applied in the non-dict branch of
_extract_final_markdown, so dict results can ignore the passed-in files map and
miss /shared/output.md or /output.md. Update _extract_final_markdown in
deep_researcher.agent so the result.get("files") / getattr(result, "files")
selection is grouped correctly and the files parameter is used as a fallback for
both dict and non-dict result shapes, then keep the existing output-path
extraction logic intact.
♻️ Duplicate comments (1)
src/aiq_agent/agents/deep_researcher/agent.py (1)

312-332: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

reason doesn't distinguish tool-unavailable vs. tool-unused cases.

The log message differentiates "all tools unavailable" (lines 313-318) from "tools available but unused" (lines 320-325), but the machine-readable reason is hardcoded to "empty_source_registry" in both cases. Downstream consumers can only infer the real cause by cross-referencing available_tool_count.

♻️ Proposed fix
+                reason = "no_tools_available" if available_count == 0 else "sources_not_captured"
                 if result is not None:
                     result["citation_verification_status"] = {
                         "status": "unverified",
-                        "reason": "empty_source_registry",
+                        "reason": reason,
                         "available_tool_count": available_count,
                         "unavailable_tools": unavailable,
                     }
🤖 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 `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 312 - 332, The
verification status in deep_researcher/agent.py uses the same hardcoded reason
for two different outcomes, so update the logic around the
citation_verification_status assignment to set a distinct machine-readable
reason based on available_count and unavailable. Use one reason for the “all
tools unavailable” path in the logger.error branch and a different one for the
“tools available but unused” path in the logger.warning branch, keeping the rest
of the result structure unchanged.
🤖 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.

Outside diff comments:
In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 182-195: The fallback to state.files is only applied in the
non-dict branch of _extract_final_markdown, so dict results can ignore the
passed-in files map and miss /shared/output.md or /output.md. Update
_extract_final_markdown in deep_researcher.agent so the result.get("files") /
getattr(result, "files") selection is grouped correctly and the files parameter
is used as a fallback for both dict and non-dict result shapes, then keep the
existing output-path extraction logic intact.

---

Duplicate comments:
In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 312-332: The verification status in deep_researcher/agent.py uses
the same hardcoded reason for two different outcomes, so update the logic around
the citation_verification_status assignment to set a distinct machine-readable
reason based on available_count and unavailable. Use one reason for the “all
tools unavailable” path in the logger.error branch and a different one for the
“tools available but unused” path in the logger.warning branch, keeping the rest
of the result structure unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 9fa6ab94-e24d-4ee0-848d-d6f9aa55eefd

📥 Commits

Reviewing files that changed from the base of the PR and between 84d08eb and 74152b1.

📒 Files selected for processing (2)
  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.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:

  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/agent.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:

  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/agent.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🧠 Learnings (1)
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🔇 Additional comments (3)
src/aiq_agent/agents/deep_researcher/agent.py (1)

274-274: LGTM!

tests/aiq_agent/agents/deep_researcher/test_agent.py (2)

1119-1149: LGTM!


1151-1173: LGTM!

@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

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

⚠️ Outside diff range comments (1)
src/aiq_agent/agents/deep_researcher/agent.py (1)

332-338: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid item assignment on result here. DeepResearchAgentState is a BaseModel, and this flow already handles dict-or-model results elsewhere. result["citation_verification_status"] = ... will raise if ainvoke returns the state object, so update the state via model_copy(update=...) or setattr before returning it.

🤖 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 `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 332 - 338, Avoid
direct item assignment on the `result` object in `DeepResearchAgentState`
handling, since `ainvoke` may return a BaseModel instance rather than a dict. In
the `DeepResearchAgent` flow where `citation_verification_status` is set for the
`empty_source_registry` case, update the result via `model_copy(update=...)` or
`setattr` depending on whether `result` is a model or dict, matching the
existing dict-or-model handling used elsewhere before returning it.
🤖 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.

Outside diff comments:
In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 332-338: Avoid direct item assignment on the `result` object in
`DeepResearchAgentState` handling, since `ainvoke` may return a BaseModel
instance rather than a dict. In the `DeepResearchAgent` flow where
`citation_verification_status` is set for the `empty_source_registry` case,
update the result via `model_copy(update=...)` or `setattr` depending on whether
`result` is a model or dict, matching the existing dict-or-model handling used
elsewhere before returning it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: f9f4a68b-fcc3-482f-99a7-e3edd2911110

📥 Commits

Reviewing files that changed from the base of the PR and between 74152b1 and ea07a49.

📒 Files selected for processing (1)
  • src/aiq_agent/agents/deep_researcher/agent.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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:

  • src/aiq_agent/agents/deep_researcher/agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/agent.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:

  • src/aiq_agent/agents/deep_researcher/agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/agent.py
🔇 Additional comments (3)
src/aiq_agent/agents/deep_researcher/agent.py (3)

333-337: reason is still hardcoded to "empty_source_registry" for both the tools-unavailable and tools-unused paths.

This was raised previously. Note the regression tests (test_run_empty_source_registry_returns_unverified_status) assert reason == "empty_source_registry", so any split of reason must update those assertions in lockstep.


141-141: LGTM!


186-191: LGTM!

@AjayThorve

Copy link
Copy Markdown
Member

/ok to test dd3a572

@AjayThorve AjayThorve added this to the v2.2 milestone Jul 14, 2026
Comment thread src/aiq_agent/agents/deep_researcher/agent.py Outdated
@AjayThorve
AjayThorve changed the base branch from develop to release/2.2 July 14, 2026 07:13

@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.

♻️ Duplicate comments (2)
src/aiq_agent/agents/deep_researcher/agent.py (2)

350-355: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not silently publish the unverified report.

As flagged in a previous review, this unverified status is retained only in the internal DeepResearchAgentState. External response boundaries discard it, making a report produced with zero captured sources indistinguishable from a verified report to users and downstream consumers. Please propagate a typed verification disposition through both job and chat responses and surface an explicit warning for unverified.

🤖 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 `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 350 - 355,
Propagate the typed verification disposition from DeepResearchAgentState through
both job and chat response boundaries, preserving “unverified” when
citation_verification_status indicates an empty source registry. Update the
external response models and serializers used by DeepResearchAgent so unverified
reports are distinguishable from verified reports, and add an explicit
user-facing warning for the unverified disposition.

349-356: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prevent TypeError on object results and distinguish the reason field.

The reason field is hardcoded to "empty_source_registry", failing to distinguish between unavailable and unused tools (as flagged in a previous review). Additionally, since result could be an object rather than a dictionary, using item assignment (result["citation_verification_status"] = ...) risks a TypeError.

  • src/aiq_agent/agents/deep_researcher/agent.py#L349-L356: Safely assign the verification status and distinguish the reason field based on tool availability.
  • tests/aiq_agent/agents/deep_researcher/test_agent.py#L1259-L1262: Update the assertion to match the distinct reason ("sources_not_captured"), since available_count will be 1 in this test.
🛠️ Proposed fixes

src/aiq_agent/agents/deep_researcher/agent.py

-                if result is not None:
-                    result["citation_verification_status"] = {
-                        "status": "unverified",
-                        "reason": "empty_source_registry",
-                        "available_tool_count": available_count,
-                        "unavailable_tools": unavailable,
-                    }
+                if result is not None:
+                    reason = "no_tools_available" if available_count == 0 else "sources_not_captured"
+                    status_payload = {
+                        "status": "unverified",
+                        "reason": reason,
+                        "available_tool_count": available_count,
+                        "unavailable_tools": unavailable,
+                    }
+                    if isinstance(result, dict):
+                        result["citation_verification_status"] = status_payload
+                    else:
+                        setattr(result, "citation_verification_status", status_payload)

tests/aiq_agent/agents/deep_researcher/test_agent.py

-            assert result.citation_verification_status["reason"] == "empty_source_registry"
+            assert result.citation_verification_status["reason"] == "sources_not_captured"
🤖 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 `@src/aiq_agent/agents/deep_researcher/agent.py` around lines 349 - 356, In the
verification-status assignment in src/aiq_agent/agents/deep_researcher/agent.py
lines 349-356, safely update both dictionary and object results without assuming
item assignment, and set reason based on tool availability so unavailable tools
remain distinct from unused tools. Update the corresponding assertion in
tests/aiq_agent/agents/deep_researcher/test_agent.py lines 1259-1262 to expect
"sources_not_captured"; no other test behavior should change.
🤖 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.

Duplicate comments:
In `@src/aiq_agent/agents/deep_researcher/agent.py`:
- Around line 350-355: Propagate the typed verification disposition from
DeepResearchAgentState through both job and chat response boundaries, preserving
“unverified” when citation_verification_status indicates an empty source
registry. Update the external response models and serializers used by
DeepResearchAgent so unverified reports are distinguishable from verified
reports, and add an explicit user-facing warning for the unverified disposition.
- Around line 349-356: In the verification-status assignment in
src/aiq_agent/agents/deep_researcher/agent.py lines 349-356, safely update both
dictionary and object results without assuming item assignment, and set reason
based on tool availability so unavailable tools remain distinct from unused
tools. Update the corresponding assertion in
tests/aiq_agent/agents/deep_researcher/test_agent.py lines 1259-1262 to expect
"sources_not_captured"; no other test behavior should change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 030809cd-617a-401f-8008-65ddd344cd21

📥 Commits

Reviewing files that changed from the base of the PR and between 74152b1 and 5b16d9b.

📒 Files selected for processing (2)
  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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/aiq_agent/agents/deep_researcher/test_agent.py
  • src/aiq_agent/agents/deep_researcher/agent.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/agent.py
🧠 Learnings (1)
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/deep_researcher/test_agent.py

@AjayThorve
AjayThorve requested a review from a team July 15, 2026 18:45
Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.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 `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 356-370: The report state currently risks storing citation-warning
text in last_report_markdown instead of clean markdown. Update the
DeepResearcherAgent result handling around report_text and
prepend_citation_verification_warning to capture or retrieve the raw report
markdown before applying the warning, use that clean value for
last_report_markdown, and retain the warning only in the visible report_message
content.
🪄 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: 7bf67f53-0898-419c-9704-57f916967901

📥 Commits

Reviewing files that changed from the base of the PR and between 5b16d9b and 9121ba5.

📒 Files selected for processing (15)
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • tests/aiq_agent/jobs/test_runner.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.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/aiq_agent/jobs/test_runner.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/jobs/test_runner.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
frontends/ui/**/*.{js,ts,jsx,tsx,vue}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run npm lint, type-check, and build validation for UI changes in frontends/ui

Files:

  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
frontends/ui/**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes

Files:

  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
frontends/ui/**/*

⚙️ CodeRabbit configuration file

frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.

Files:

  • frontends/ui/src/adapters/api/index.ts
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.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
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
🧠 Learnings (1)
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🔇 Additional comments (17)
src/aiq_agent/agents/deep_researcher/models/state.py (1)

28-87: LGTM!

Also applies to: 125-125

src/aiq_agent/agents/deep_researcher/models/__init__.py (1)

16-22: LGTM!

Also applies to: 43-57

src/aiq_agent/agents/deep_researcher/agent.py (1)

33-33: LGTM!

Also applies to: 44-48, 279-286, 347-371, 398-404

tests/aiq_agent/agents/deep_researcher/test_agent.py (1)

1233-1267: LGTM!

Also applies to: 1268-1296, 1299-1321

tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

848-888: LGTM!

frontends/aiq_api/src/aiq_api/jobs/runner.py (2)

827-829: LGTM!


1250-1258: LGTM!

frontends/ui/src/adapters/api/index.ts (1)

33-37: LGTM!

Also applies to: 113-123

frontends/ui/src/features/chat/hooks/use-load-job-data.ts (3)

29-29: LGTM!


262-268: LGTM!


336-342: LGTM!

frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts (1)

98-105: LGTM!

Also applies to: 189-213, 436-439, 461-461, 470-472, 482-485, 519-521

frontends/aiq_api/src/aiq_api/routes/jobs.py (1)

51-51: LGTM!

Also applies to: 401-418, 1166-1168

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

189-207: LGTM!

tests/aiq_agent/jobs/test_runner.py (1)

606-630: LGTM!

frontends/ui/src/adapters/api/deep-research-client.ts (1)

42-54: LGTM!

Also applies to: 779-779, 798-808

frontends/ui/src/adapters/api/deep-research-client.spec.ts (1)

5-9: LGTM!

Also applies to: 38-57

Comment thread src/aiq_agent/agents/chat_researcher/agent.py Outdated

@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 `@tests/aiq_agent/agents/chat_researcher/test_agent.py`:
- Around line 981-984: Update the assertions in the relevant chat researcher
test to derive the expected warning through the imported
citation_verification_warning function instead of hardcoding its user-facing
string. Preserve the existing checks that the final message begins with the
warning and contains it exactly once, along with the last_report_markdown
assertion.
🪄 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: 21109bf7-fde6-4cc0-a1f9-cf72e7368f77

📥 Commits

Reviewing files that changed from the base of the PR and between c682e0d and 8d473cc.

📒 Files selected for processing (4)
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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:

  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/agent.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/agent.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
🧠 Learnings (1)
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
🔇 Additional comments (3)
src/aiq_agent/agents/deep_researcher/models/state.py (1)

88-97: LGTM!

src/aiq_agent/agents/deep_researcher/models/__init__.py (1)

23-59: LGTM!

src/aiq_agent/agents/chat_researcher/agent.py (1)

388-405: LGTM!

Comment thread tests/aiq_agent/agents/chat_researcher/test_agent.py Outdated
@AjayThorve

Copy link
Copy Markdown
Member

/ok to test 3670801

@AjayThorve AjayThorve left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remaining citation-verification contract findings on the current head.

clarifier_result: Log from clarifier agent dialog.
available_documents: User-uploaded documents with summaries for context.
citation_verification_status: Set when citation verification was skipped
because the source registry was empty. ``None`` means the report was

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P1] Do not equate missing status with verified

The new contract says None means the report was verified, but the control flow also leaves it None when enable_citation_verification=False and when verification runs with a nonempty registry but finds zero valid citations. In the latter case, a report with no citation markers is returned unchanged and the API/UI omit the warning even though no claims were verified.

Make the verification engine return an explicit closed outcome for every run—at minimum verified, unverified, or disabled—with machine-readable reasons such as no_sources and no_valid_citations. Propagate that outcome instead of inferring success from absence.

# Apply caller metadata first, then set the canonical report last so a
# stray "report" key in output_metadata can never overwrite the real report.
output = {**(output_metadata or {}), "report": report}
citation_verification_status = _extract_citation_verification_status(result)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P1] Preserve unverified disposition across derived reports

This extracts the disposition only from the current agent result. ReportRewriterAgentState has no citation status, and report_output_metadata(parent_job_id, "edit") does not carry the parent disposition, so an edit of an unverified parent is persisted and returned with citation_verification_status=null. The warning is also flattened into report text before persistence, so the rewrite model can alter or drop the only remaining trust signal.

Treat unverified as monotonic through report edits and parent-seeded research unless the complete derived report is reverified. Carry the disposition through ReportContext and output metadata, and keep canonical report text separate from presentation warnings.

class CitationVerificationStatusResponse(BaseModel):
"""Public citation-verification disposition for a generated report."""

status: str = Field(..., description="Citation verification status, for example 'unverified'")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P2] Make the public disposition a closed domain type

This new API exposes unrestricted str fields while the agent state uses dict[str, Any] and the TypeScript client uses plain string. Invalid status/reason combinations are representable, and public_citation_verification_status() silently discards any future status other than unverified.

Define the authoritative CitationVerificationOutcome alongside CitationVerificationResult in common.citation_verification, use Literal or enum values for status and reason, and map that type into the API DTO. User-facing warning copy should be rendered at the response/UI boundary rather than defining the domain contract.

@AjayThorve AjayThorve removed this from the v2.2 milestone Jul 17, 2026
@AjayThorve
AjayThorve changed the base branch from release/2.2 to develop July 17, 2026 21:25
Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.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 `@src/aiq_agent/agents/chat_researcher/agent.py`:
- Around line 472-481: Update the inline report edit return in report_edit_node
to compute the combined citation verification status, retain clean revised in
last_report_markdown, and pass the visible message content through
prepend_citation_verification_warning using that status, matching
deep_research_node 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: 301eac61-5aa6-4c08-807e-256189fe95fe

📥 Commits

Reviewing files that changed from the base of the PR and between 2f61174 and 021464a.

📒 Files selected for processing (23)
  • frontends/aiq_api/src/aiq_api/jobs/report_context.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/aiq_api/tests/test_report_context.py
  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/report_rewriter/models.py
  • src/aiq_agent/common/__init__.py
  • src/aiq_agent/common/citation_verification.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/common/test_citation_verification.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • tests/aiq_agent/jobs/test_runner.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.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/aiq_agent/jobs/test_runner.py
  • src/aiq_agent/agents/report_rewriter/models.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • src/aiq_agent/common/__init__.py
  • frontends/aiq_api/tests/test_report_context.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • frontends/aiq_api/src/aiq_api/jobs/runner.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • tests/aiq_agent/common/test_citation_verification.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • frontends/aiq_api/src/aiq_api/jobs/report_context.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/common/citation_verification.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/aiq_agent/jobs/test_runner.py
  • tests/aiq_agent/fastapi_extensions/test_deep_research.py
  • frontends/aiq_api/tests/test_report_context.py
  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/common/test_citation_verification.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
src/aiq_agent/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/aiq_agent/**/*.py: Respect authenticated data sources by honoring requires_auth, per-user token pass-through, and backend token validators; apply owner guardrails before loading protected report or artifact context into an agent
Do not weaken or bypass AuthMiddleware, validators, or auth gating without a prior design discussion

Files:

  • src/aiq_agent/agents/report_rewriter/models.py
  • src/aiq_agent/common/__init__.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
  • src/aiq_agent/common/citation_verification.py
src/aiq_agent/agents/**/*

⚙️ CodeRabbit configuration file

src/aiq_agent/agents/**/*: Review agent changes for research workflow correctness, graph state transitions, prompt/tool contracts,
HITL behavior, and failure handling. Flag changes that weaken source attribution, report generation,
async cancellation, checkpointing, or data-source selection without focused tests and docs.

Files:

  • src/aiq_agent/agents/report_rewriter/models.py
  • src/aiq_agent/agents/chat_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/models/__init__.py
  • src/aiq_agent/agents/deep_researcher/models/state.py
  • src/aiq_agent/agents/deep_researcher/agent.py
  • src/aiq_agent/agents/chat_researcher/register.py
  • src/aiq_agent/agents/report_rewriter/agent.py
  • src/aiq_agent/agents/chat_researcher/agent.py
frontends/ui/**/*.{js,ts,jsx,tsx,vue}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run npm lint, type-check, and build validation for UI changes in frontends/ui

Files:

  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
frontends/ui/**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes

Files:

  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
frontends/ui/**/*

⚙️ CodeRabbit configuration file

frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.

Files:

  • frontends/ui/src/adapters/api/deep-research-client.spec.ts
  • frontends/ui/src/adapters/api/deep-research-client.ts
  • frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts
{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/jobs/runner.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/aiq_api/src/aiq_api/jobs/report_context.py
🧠 Learnings (2)
📚 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_report_context.py
📚 Learning: 2026-07-06T23:55:42.908Z
Learnt from: cdgamarose-nv
Repo: NVIDIA-AI-Blueprints/aiq PR: 311
File: src/aiq_agent/agents/deep_researcher/prompts/orchestrator.j2:74-81
Timestamp: 2026-07-06T23:55:42.908Z
Learning: In agent test files (e.g., tests/aiq_agent/agents/*/test_agent.py), avoid brittle assertions that match exact substrings from prompt template files (such as *.j2 prompt wording). Prompt wording can change frequently, so instead assert structural/behavioral properties (e.g., that the prompt builder is called, that required sections/fields are present via stable markers, that the model output/agent behavior conforms to an expected schema, or that key actions are taken) rather than matching literal prompt text.

Applied to files:

  • tests/aiq_agent/agents/chat_researcher/test_agent.py
  • tests/aiq_agent/agents/report_rewriter/test_agent.py
  • tests/aiq_agent/agents/deep_researcher/test_agent.py
🪛 ast-grep (0.44.1)
tests/aiq_agent/agents/report_rewriter/test_agent.py

[info] 135-140: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"parent_job_id": "parent-job",
"citation_verification_status": {"status": "unverified", "reason": "no_sources"},
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (27)
frontends/aiq_api/src/aiq_api/jobs/report_context.py (1)

18-18: LGTM!

Also applies to: 49-49, 70-74, 195-200, 233-234, 237-260, 314-328

frontends/aiq_api/src/aiq_api/jobs/runner.py (1)

819-837: LGTM!

Also applies to: 1262-1272

frontends/aiq_api/src/aiq_api/routes/jobs.py (1)

51-53: LGTM!

Also applies to: 403-420, 894-898, 1172-1174

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

185-213: LGTM!

Also applies to: 295-306

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

189-207: LGTM!

tests/aiq_agent/jobs/test_runner.py (1)

606-626: LGTM!

frontends/ui/src/adapters/api/deep-research-client.ts (1)

42-59: LGTM!

Also applies to: 784-784, 803-813

frontends/ui/src/adapters/api/deep-research-client.spec.ts (1)

5-9: LGTM!

Also applies to: 38-57

frontends/ui/src/features/chat/hooks/use-load-job-data.spec.ts (1)

98-105: LGTM!

Also applies to: 189-213, 436-439, 461-461, 470-472, 482-485, 519-521

src/aiq_agent/common/citation_verification.py (2)

133-198: LGTM!


1083-1121: LGTM!

src/aiq_agent/agents/deep_researcher/models/state.py (2)

63-110: LGTM!


130-147: LGTM!

src/aiq_agent/agents/deep_researcher/models/__init__.py (1)

49-72: LGTM!

src/aiq_agent/common/__init__.py (1)

81-90: LGTM!

src/aiq_agent/agents/deep_researcher/agent.py (1)

353-382: LGTM!

tests/aiq_agent/agents/deep_researcher/test_agent.py (3)

1233-1267: LGTM!


1299-1348: LGTM!


1696-1703: LGTM!

src/aiq_agent/agents/chat_researcher/agent.py (1)

389-408: LGTM!

src/aiq_agent/agents/chat_researcher/models/state.py (1)

43-47: LGTM!

Also applies to: 86-86

src/aiq_agent/agents/report_rewriter/agent.py (1)

8-11: LGTM!

Also applies to: 25-26, 59-66, 80-101, 111-118, 135-155, 182-182, 235-243, 255-255

src/aiq_agent/agents/report_rewriter/models.py (1)

32-32: LGTM!

src/aiq_agent/agents/chat_researcher/register.py (1)

419-422: LGTM!

Also applies to: 456-476, 535-539

tests/aiq_agent/common/test_citation_verification.py (1)

550-567: LGTM!

Also applies to: 579-580, 1107-1125

tests/aiq_agent/agents/report_rewriter/test_agent.py (1)

122-122: LGTM!

Also applies to: 123-145

tests/aiq_agent/agents/chat_researcher/test_agent.py (1)

31-31: LGTM!

Also applies to: 943-986

Comment thread src/aiq_agent/agents/chat_researcher/agent.py Outdated
Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
@cdgamarose-nv

Copy link
Copy Markdown
Collaborator

@rkarmaka Following up - would you be able to address the PR comments and resolve merge conflicts?

rkarmaka and others added 4 commits August 20, 2026 20:27
…pty-source-registry

Brings in upstream 2.2.1 hardening (NVIDIA-AI-Blueprints#454, NVIDIA-AI-Blueprints#455) and configurable shallow
citation enforcement (NVIDIA-AI-Blueprints#456). No textual conflicts: upstream's change to
_extract_title_for_url (HTML-escaped URL matching) is disjoint from this
branch's citation-verification disposition helpers in the same file.

Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
Signed-off-by: Ranit Karmakar <karmakarranit6@gmail.com>
@cdgamarose-nv

Copy link
Copy Markdown
Collaborator

Thanks again for working through this and for keeping the branch updated. Since this PR was opened, #397/#405 changed the empty-source behavior: AI-Q now preserves the sanitized report, returns an actionable typed failure, and makes the report available through the report endpoint. That addresses the original report-loss problem.

After the latest merges, this PR also no longer removes the empty-source exception—the agent still raises before the new verification status is set. The remaining changes are now fairly broad, and there are a couple of unresolved concerns, including empty-source reports not receiving the new status and verification-disabled reports potentially being promoted to “verified” during follow-up.

Given how the underlying behavior has evolved, I’m going to close this PR as no longer needed. If you can still reproduce a user-facing gap on the current develop branch, please reopen the issue (or open a focused new one) with the current reproduction steps. We’d be happy to look at a smaller change targeted specifically at that remaining behavior.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants