Skip to content

Forward-merge release/2.2 into develop - #366

Merged
GPUtester merged 1 commit into
developfrom
release/2.2
Jul 17, 2026
Merged

Forward-merge release/2.2 into develop#366
GPUtester merged 1 commit into
developfrom
release/2.2

Conversation

@rapids-bot

@rapids-bot rapids-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

Forward-merge triggered by push to release/2.2 that creates a PR to keep develop up-to-date. If this PR is unable to be immediately merged due to conflicts, it will remain open for the team to manually merge. See forward-merger docs for more info.

…ct (#360)

#### Overview

The `aiq-research` skill helper (`skills/aiq-research/scripts/aiq.py`) had two contract mismatches with the 26.07 backend. Both were verified to still reproduce at `release/2.2` HEAD, and the fix was checked against the backend source that defines each contract.

**1. `interrupted` was not a terminal job state.** `_DONE_JOB_STATES` and `_FAILED_JOB_STATES` omitted `interrupted`, but the backend sets a cancelled job to that state (`JobStatus.INTERRUPTED = "interrupted"` in `nat` `async_jobs/job_store.py`; the cancel route in `frontends/aiq_api/.../routes/jobs.py` returns `{"status": "interrupted"}`). Because the poll loop only exits on a member of `_DONE_JOB_STATES`, a cancelled job kept polling every 15s until the 3600s timeout. Adding `interrupted` to both sets makes polling stop immediately and report the job as failed rather than completed successfully.

**2. Deep-research escalation was detected only in the legacy text format.** `_command_chat` matched only `Job ID: <uuid>`, so the backend's structured escalation payload was printed raw and never surfaced as `deep_research_running`, leaving the documented `SKILL.md` Step 2/3 flow stuck. The backend emits the escalation as a compact JSON object placed in the assistant message content (`_job_escalation_message` in `src/aiq_agent/agents/chat_researcher/agent.py`):

```json
{"type": "job_escalation", "kind": "deep_research", "job_id": "<uuid>"}
```

A new `_detect_deep_research_escalation` helper recognizes this object both as the top-level `/chat` result and as JSON embedded in the message content, validates the `job_id` as a UUID, and emits the documented `{"status": "deep_research_running", "job_id": "<uuid>"}`. It is tried before the legacy `Job ID:` regex, which is retained for backward compatibility. Non-`deep_research` kinds (e.g. `report_edit`), malformed JSON, non-escalation JSON, and missing/invalid job IDs are deliberately ignored so they cannot produce a false `deep_research_running`.

No `SKILL.md` prose change is required: the emitted shape is unchanged, so the existing Steps 2–4 flow now advances as documented.

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

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

#### Validation

Run from the repo root:

```bash
uv run pytest tests/scripts/test_aiq_research_helper.py -q      # 12 passed
uv run ruff check skills/aiq-research/scripts/aiq.py tests/scripts/test_aiq_research_helper.py   # All checks passed
uv run pre-commit run --files skills/aiq-research/scripts/aiq.py tests/scripts/test_aiq_research_helper.py   # ruff, ruff-format, detect-secrets, EOF/whitespace all pass
```

Contract verification against `release/2.2` source (no live 26.07 backend was required, and the fix was not validated against assumptions alone):
- SK-1: `JobStatus.INTERRUPTED = "interrupted"` (nat `async_jobs/job_store.py`); cancel route returns `{"status": "interrupted"}` (`frontends/aiq_api/src/aiq_api/routes/jobs.py`).
- SK-2: `_job_escalation_message(kind, job_id)` returns `{"type":"job_escalation","kind":..., "job_id":...}` and is delivered as `AIMessage(content=...)` (`src/aiq_agent/agents/chat_researcher/agent.py`), matching the "escalation embedded in message content" path the helper handles.

New test matrix (`tests/scripts/test_aiq_research_helper.py`, loaded via `importlib` to match the standalone-script tests already in `tests/scripts/`):
- `interrupted` membership in the terminal/failed state sets;
- `poll_until_complete` returns on the first `interrupted` status (one status call, zero sleeps);
- `research_poll` exits failure on `interrupted` without another poll cycle and without fetching a report;
- JSON escalation detected as top-level result and as embedded content;
- `_command_chat` emits `deep_research_running`;
- legacy `Job ID: <uuid>` still detected;
- guards: malformed JSON, non-escalation JSON, unsupported `kind`, missing/invalid/non-string `job_id`, and shallow-answer fall-through.

- [x] I ran the relevant local checks or explained why they are not applicable.
- [x] I added or updated tests for behavior changes.
- [x] I updated documentation for user-facing or contributor-facing changes.  
- [x] I confirmed this PR does not include secrets, credentials, or internal-only data.
- [x] I certify this contribution under the Developer Certificate of Origin (DCO) and signed my commits with `git commit -s` or an equivalent sign-off.
- [x] I replaced the DCO sign-off placeholder with my GitHub commit identity and kept the required angle brackets around the email address.

#### Where should reviewers start?

- `skills/aiq-research/scripts/aiq.py`: the state-set change (`_DONE_JOB_STATES` / `_FAILED_JOB_STATES`) and the new `_escalation_job_id` / `_detect_deep_research_escalation` helpers plus the reworked `_command_chat` ordering (JSON escalation first, legacy regex retained).
- `tests/scripts/test_aiq_research_helper.py`: the guard cases confirm no false `deep_research_running` on malformed / non-escalation / unsupported-kind / invalid-`job_id` payloads.

#### Related Issues



## Summary by CodeRabbit

* **Bug Fixes**
  * Deep-research escalations are now detected reliably from chat responses.
  * Valid job IDs are reported with a `deep_research_running` status.
  * Interrupted research jobs are treated as terminal failures and stop polling promptly.
  * Invalid or malformed job IDs now safely fall back to displaying the original response.

* **Tests**
  * Added coverage for escalation formats, interrupted jobs, legacy job-ID parsing, and malformed responses.

Authors:
  - Tanner Leach (https://github.com/tanleach)

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

URL: #360
@rapids-bot
rapids-bot Bot requested a review from a team July 17, 2026 20:40
@GPUtester
GPUtester merged commit 135f048 into develop Jul 17, 2026
@rapids-bot

rapids-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Author

SUCCESS - forward-merge complete.

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