Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/docs/extraction/workflow-agentic-retrieval.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,18 @@ curl -X POST http://localhost:7670/v1/query \
-d '{"query": "find documents about parser behavior", "top_k": 5, "agentic": true}'
```

The service-query CLI sends the same request when you pass `--agentic`:

```bash
retriever query service "find documents about parser behavior" \
--service-url http://localhost:7670 \
--agentic
```

This command uses the service's configured agentic LLM and embedding endpoints.
It does not start a local agent LLM or accept the local query command's
`--agentic-llm-model` and `--agentic-invoke-url` options.

When service auth is enabled, send `Authorization: Bearer <token>` (`NEMO_RETRIEVER_API_TOKEN`). Requests with `agentic: true` return HTTP `400` when agentic retrieval is not configured on the service.

`top_k` cannot exceed the configured `agentic.backend_top_k` (default 20). Agentic queries are capped at 4,096 characters.
Expand Down
12 changes: 12 additions & 0 deletions nemo_retriever/docs/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ retriever query service "What is in this corpus?" \
--service-url http://localhost:7670
```

To run the service's configured agentic retrieval workflow, add `--agentic`:

```bash
retriever query service "What is in this corpus?" \
--service-url http://localhost:7670 \
--agentic
```

The service supplies the agent LLM and embedding configuration. This command
does not support local agent settings such as `--agentic-llm-model` or
`--agentic-invoke-url`.

### Route ingest to hosted or self-hosted NIM endpoints

```bash
Expand Down
2 changes: 2 additions & 0 deletions nemo_retriever/src/nemo_retriever/cli/query/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ def _service_command(
content_types: opts.ContentTypesOption = None,
output_format: opts.OutputFormatOption = "hits",
max_text_chars: opts.MaxTextCharsOption = None,
agentic: opts.AgenticOption = False,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Agentic evidence mislabeled semantic

When --agentic is combined with --format evidence, the command runs the service's agentic workflow but still passes strategies=["semantic"] to output shaping, causing coverage.strategies_used to report incorrect provenance.

Prompt To Fix With AI
This is a comment left during a code review.
Path: nemo_retriever/src/nemo_retriever/cli/query/app.py
Line: 340

Comment:
**Agentic evidence mislabeled semantic**

When `--agentic` is combined with `--format evidence`, the command runs the service's agentic workflow but still passes `strategies=["semantic"]` to output shaping, causing `coverage.strategies_used` to report incorrect provenance.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

) -> None:
_validate_output_options(output_format, max_text_chars)
silence_noisy_libraries()
Expand All @@ -355,6 +356,7 @@ def _service_command(
service_url=service_url,
service_api_token=service_api_token,
),
agentic=agentic,
)
)
except ROOT_CLI_ERRORS as exc:
Expand Down
1 change: 1 addition & 0 deletions nemo_retriever/src/nemo_retriever/query/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@ class ServiceQueryRequest:
query: str
retrieval: QueryRetrievalOptions = field(default_factory=QueryRetrievalOptions)
service: QueryServiceOptions = field(default_factory=QueryServiceOptions)
agentic: bool = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Validate the agentic request setting

The new user-facing agentic setting is added to an unvalidated dataclass without descriptive field metadata, so unsupported option combinations are not rejected at request construction and instead fail later at the remote service boundary.

Rule Used: User-facing configuration must use Pydantic models... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: nemo_retriever/src/nemo_retriever/query/options.py
Line: 95

Comment:
**Validate the agentic request setting**

The new user-facing `agentic` setting is added to an unvalidated dataclass without descriptive field metadata, so unsupported option combinations are not rejected at request construction and instead fail later at the remote service boundary.

**Rule Used:** User-facing configuration must use Pydantic models... ([source](https://github.com/nvidia/nemo-retriever/blob/f41b14e714a1883d2d8640ff2c23991b7ed9ca6d/nemo_retriever/.greptile/config.json))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

2 changes: 1 addition & 1 deletion nemo_retriever/src/nemo_retriever/query/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def query_documents(request: ServiceQueryRequest) -> list[RetrievalHit]:
base_url=request.service.service_url,
api_token=request.service.service_api_token,
)
raw_result_sets = client.query(request.query, top_k=retrieval_top_k)
raw_result_sets = client.query(request.query, top_k=retrieval_top_k, agentic=request.agentic)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Candidate pool exceeds agentic depth

When an agentic service query has a valid final top_k but a candidate_k above the configured agentic.backend_top_k, this call sends candidate_k as the endpoint's top_k, causing the service to reject the request with HTTP 422.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: nemo_retriever/src/nemo_retriever/query/service.py
Line: 30

Comment:
**Candidate pool exceeds agentic depth**

When an agentic service query has a valid final `top_k` but a `candidate_k` above the configured `agentic.backend_top_k`, this call sends `candidate_k` as the endpoint's `top_k`, causing the service to reject the request with HTTP 422.

**Knowledge Base Used:**
- [Query workflow orchestration](https://app.greptile.com/nvidia-public-github/-/custom-context/knowledge-base/nvidia/nemo-retriever/-/docs/query-workflow-orchestration.md)
- [Retriever service](https://app.greptile.com/nvidia-public-github/-/custom-context/knowledge-base/nvidia/nemo-retriever/-/docs/retriever-service.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

raw_hits = raw_result_sets[0]
return shape_query_hits(
raw_hits,
Expand Down
6 changes: 5 additions & 1 deletion nemo_retriever/src/nemo_retriever/service/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,15 @@ def query(
*,
top_k: int,
collection_name: str | None = None,
agentic: bool = False,
) -> list[list[dict[str, Any]]] | list[QueryHit]:
"""Search ingested documents through ``POST /v1/query``.

Note:
``top_k`` is required here but defaults to 10 on :meth:`aquery`.
That asymmetry is part of the released signature; do not unify it.
"""
Comment on lines +556 to 563

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Document the agentic parameter

The public query() and aquery() methods add agentic without documenting its behavior or single-query restriction, leaving library users unable to discover this changed request contract from the API documentation.

Rule Used: Every public class and function in nemo_retriever ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: nemo_retriever/src/nemo_retriever/service/client.py
Line: 556-563

Comment:
**Document the agentic parameter**

The public `query()` and `aquery()` methods add `agentic` without documenting its behavior or single-query restriction, leaving library users unable to discover this changed request contract from the API documentation.

**Rule Used:** Every public class and function in nemo_retriever ... ([source](https://github.com/nvidia/nemo-retriever/blob/f41b14e714a1883d2d8640ff2c23991b7ed9ca6d/nemo_retriever/.greptile/config.json))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

return self._run(self.aquery(query, top_k=top_k, collection_name=collection_name))
return self._run(self.aquery(query, top_k=top_k, collection_name=collection_name, agentic=agentic))

def _query_hit(self, hit: dict[str, Any]) -> QueryHit:
return self._model(
Expand All @@ -580,12 +581,15 @@ async def aquery(
*,
top_k: int = 10,
collection_name: str | None = None,
agentic: bool = False,
) -> list[list[dict[str, Any]]] | list[QueryHit]:
"""Asynchronously search through ``POST /v1/query``."""

payload: dict[str, Any] = {"query": query, "top_k": int(top_k)}
if collection_name:
payload["collection_name"] = collection_name
if agentic:
Comment on lines +584 to +591

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Reject batched agentic queries

When query() or aquery() receives a list of query strings with agentic=True, the client serializes both values even though the service requires a single string for agentic mode, causing the request to fail service validation instead of returning results.

Prompt To Fix With AI
This is a comment left during a code review.
Path: nemo_retriever/src/nemo_retriever/service/client.py
Line: 584-591

Comment:
**Reject batched agentic queries**

When `query()` or `aquery()` receives a list of query strings with `agentic=True`, the client serializes both values even though the service requires a single string for agentic mode, causing the request to fail service validation instead of returning results.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

payload["agentic"] = True
body = await self._arequest("POST", "/v1/query", json=payload)
try:
parsed = QueryResponse.model_validate(body).hits_by_query(
Expand Down
6 changes: 3 additions & 3 deletions nemo_retriever/tests/test_query_workflow_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ class FakeServiceClient:
def __init__(self, *, base_url: str, api_token: str | None = None, **_kwargs: Any) -> None:
client_calls.append({"base_url": base_url, "api_token": api_token})

def query(self, query: str, *, top_k: int) -> list[list[dict[str, Any]]]:
client_calls.append({"query": query, "top_k": top_k})
def query(self, query: str, *, top_k: int, agentic: bool = False) -> list[list[dict[str, Any]]]:
client_calls.append({"query": query, "top_k": top_k, "agentic": agentic})
return [
[
{"text": "keep", "source": "doc.pdf", "page_number": 1, "metadata": {"type": "text"}},
Expand All @@ -217,7 +217,7 @@ def query(self, query: str, *, top_k: int) -> list[list[dict[str, Any]]]:
]
assert client_calls == [
{"base_url": "http://svc:7670", "api_token": "secret"},
{"query": "deployment?", "top_k": 3},
{"query": "deployment?", "top_k": 3, "agentic": False},
]


Expand Down
17 changes: 17 additions & 0 deletions nemo_retriever/tests/test_root_query_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,7 @@ def test_root_query_service_help_hides_local_only_options() -> None:
assert "--content-types" in result.output
assert "--format" in result.output
assert "--max-text-chars" in result.output
assert "--agentic" in result.output
assert "--run-mode" not in result.output
assert "--lancedb-uri" not in result.output
assert "--table-name" not in result.output
Expand Down Expand Up @@ -991,11 +992,27 @@ def fake_query_documents(request: Any) -> list[dict[str, Any]]:
assert request.retrieval.candidate_k == 5
assert request.retrieval.page_dedup is True
assert request.retrieval.content_types == "text"
assert request.agentic is False
assert json.loads(result.output) == [
{"modality": "text", "page_number": 3, "score": 0.2, "source": "doc.pdf", "text": "service passage"},
]


def test_root_query_service_forwards_agentic_flag(monkeypatch) -> None:
requests: list[Any] = []

def fake_query_documents(request: Any) -> list[dict[str, Any]]:
requests.append(request)
return []

monkeypatch.setattr(query_cli_app, "query_service_documents", fake_query_documents)

result = RUNNER.invoke(cli_main.app, ["query", "service", "deployment?", "--agentic"])

assert result.exit_code == 0
assert requests[0].agentic is True


def test_root_query_service_mode_rejects_local_storage_flags() -> None:
result = RUNNER.invoke(
cli_main.app,
Expand Down
9 changes: 9 additions & 0 deletions nemo_retriever/tests/test_service_query_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ def test_service_client_query_accepts_empty_hits(monkeypatch) -> None:
assert RetrieverServiceClient(base_url="http://svc:7670").query("deployment?", top_k=2) == [[]]


def test_service_client_query_sends_agentic_flag(monkeypatch) -> None:
calls: list[dict[str, Any]] = []
_install_query_response(monkeypatch, {"results": [{"hits": []}]}, calls)

RetrieverServiceClient(base_url="http://svc:7670").query("deployment?", top_k=2, agentic=True)

assert calls[1]["json"] == {"query": "deployment?", "top_k": 2, "agentic": True}


@pytest.mark.parametrize(
("body", "match"),
[
Expand Down
Loading