Skip to content

feat(aiq-3.0): add initial version of GSF as a data source - #427

Merged
cdgamarose-nv merged 12 commits into
NVIDIA-AI-Blueprints:developfrom
soumilinandi:feat/gsf-query-tools
Aug 7, 2026
Merged

feat(aiq-3.0): add initial version of GSF as a data source#427
cdgamarose-nv merged 12 commits into
NVIDIA-AI-Blueprints:developfrom
soumilinandi:feat/gsf-query-tools

Conversation

@soumilinandi

@soumilinandi soumilinandi commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds the initial GSF integration as an independent sources/gsf package and NAT function group.

  • Adds a typed asynchronous GSF client with bounded responses, row limits, retries, normalized errors, and SSE parsing.
  • Exposes gsf__text_to_sql and gsf__catalog_search.
  • Forwards request-scoped AI-Q bearer tokens by default.
  • Supports optional password-session authentication for development and evaluation.
  • Maps optional database_name inputs to GSF’s target_db.
  • Preserves generated SQL, bounded rows, semantic fields, and GSF thoughts, while excluding compatibility prose from SQL evidence.
  • Adds package installation, configuration validation, documentation, and focused tests.

DCO sign-off for the squash commit

Signed-off-by: Soumili Nandi soumilin@nvidia.com

Validation

  • .venv/bin/ruff check sources/gsf — passed.

  • .venv/bin/ruff format --check sources/gsf — 10 files already formatted.

  • .venv/bin/pytest sources/gsf/tests — 30 passed.

  • Manually smoke-tested password authentication, catalog search, text-to-SQL, target_db forwarding, and parallel sessions against the GSF development deployment.

  • I ran the relevant local checks or explained why they are not applicable.

  • I added or updated tests for behavior changes.

  • I updated documentation for user-facing or contributor-facing changes.

  • I confirmed this PR does not include secrets, credentials, or internal-only data.

  • I certify this contribution under the Developer Certificate of Origin (DCO) and signed my commits with git commit -s or an equivalent sign-off.

  • I replaced the DCO sign-off placeholder with my GitHub commit identity and kept the required angle brackets around the email address.

Where should reviewers start?

Start with sources/gsf/src/gsf/register.py for the NAT function-group boundary and exposed tools, followed by sources/gsf/src/gsf/client.py for authentication, request handling, SSE parsing, response normalization, and bounds.

Focused coverage is under sources/gsf/tests/.

Related Issues

  • None.

Summary by CodeRabbit

  • New Features
    • Added GSF data-source integration with catalog search, natural-language SQL generation, and PQL generation.
    • Added streaming responses, authentication, retries, bounded results, and connection reuse.
    • Added structured errors with request IDs and retry guidance.
  • Bug Fixes
    • Improved configuration validation for tools declared individually or in function groups.
  • Documentation
    • Added setup and usage guidance for GSF capabilities, authentication, connection reuse, and catalog search.

@soumilinandi
soumilinandi requested a review from a team August 7, 2026 00:19
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds the aiq-gsf data source with typed GSF contracts, an asynchronous HTTP client, NAT function-group tools, setup integration, documentation, tests, and function_groups configuration validation.

Changes

GSF data source

Layer / File(s) Summary
Package and API contracts
sources/gsf/pyproject.toml, sources/gsf/src/gsf/__init__.py, sources/gsf/src/gsf/errors.py, sources/gsf/src/gsf/models.py, sources/gsf/tests/*
Adds package metadata, public exports, typed request and response models, standardized errors, fixtures, and contract tests.
GSF HTTP client
sources/gsf/src/gsf/client.py, sources/gsf/tests/test_client.py
Adds authenticated HTTP operations, password sessions, retries, bounded reads, SSE parsing, response normalization, and error mapping.
Function-group integration
sources/gsf/src/gsf/register.py, sources/gsf/tests/test_register.py
Registers catalog_search and text_to_sql with token resolution, trace propagation, shared client reuse, response serialization, and structured errors.
Workspace and configuration wiring
pyproject.toml, scripts/setup.sh, .agents/skills/aiq-configure-workflow/scripts/validate_config.py, sources/gsf/README.md
Adds workspace installation and setup wiring, documents GSF configuration, and validates tools declared in functions or function_groups.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant gsf_function_group
  participant GSFClient
  participant GSFHTTPAPI
  Caller->>gsf_function_group: invoke catalog_search or text_to_sql
  gsf_function_group->>GSFClient: resolve authentication and submit request
  GSFClient->>GSFHTTPAPI: send authenticated HTTP request
  GSFHTTPAPI-->>GSFClient: return JSON or SSE response
  GSFClient-->>gsf_function_group: return typed response or GSFError
  gsf_function_group-->>Caller: return JSON result or GSFToolError
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title uses a valid Conventional Commits format, has a lowercase scope, summarizes the change, and is 58 characters long.
Description check ✅ Passed The description covers the overview, DCO sign-off, validation results, reviewer starting points, and related issues.
Docstring Coverage ✅ Passed Docstring coverage is 82.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

🤖 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 @.agents/skills/aiq-configure-workflow/scripts/validate_config.py:
- Around line 232-235: Update the function_groups handling in the configuration
validator to inspect the raw data.get("function_groups") value before applying
any empty fallback, and report a validation error or reject every non-mapping
value, including empty lists and scalars. Preserve valid mapping behavior and
add regression tests covering valid groups plus invalid list and scalar
declarations; run the requested Ruff checks and pytest.

In `@sources/gsf/pyproject.toml`:
- Around line 4-6: Update the [build-system] requires declaration in
pyproject.toml to remove the unused setuptools-scm>=8 dependency while
preserving setuptools >= 83 and the existing static version configuration.

In `@sources/gsf/README.md`:
- Line 28: Update the public README examples’ GSF_BASE_URL values to remove the
internal gsf hostname, using an unset-variable form or a neutral local-only
endpoint consistently at both occurrences.
- Around line 48-55: Update the password-auth lifecycle wording in the GSF
README around the local-development configuration and password-mode explanation
to match GSFClient.from_config: state that the session is created when the
function group/client is initialized, not only when a tool is invoked. Keep the
environment-variable credential setup and configuration example unchanged.
- Around line 81-85: Remove the documented database-scoping guarantee from the
catalog search flow and reject any non-empty database_name before calling the
GSF question-entity-coverage endpoint. Update the relevant request or validation
logic to fail clearly, revise the README contract accordingly, and add a
regression test covering rejection of database-scoped searches.

In `@sources/gsf/src/gsf/client.py`:
- Around line 34-35: Update GSFClient.__init__ and GSFFunctionGroupConfig to
accept a max_connections setting defaulting to 20, create explicit httpx.Limits
using that value, and pass the limits when constructing AsyncClient so the
documented shared pool is bounded.
- Around line 437-441: Update the response parsing assignments in the client
method containing _normalize_rows and _normalize_columns to use truthiness-based
fallback between the primary and alias keys, so null or empty primary values
consult sql_response_from_db and sql_columns. Preserve the existing
normalization, truncation, and column-processing behavior.
- Around line 262-300: Update _sign_in_with_password to send the same Origin and
Referer headers as _sign_out_password_session, using self._base_url for both
values. Preserve the existing sign-in error handling and request payload, and
update the relevant mock transport assertion so the sign-in headers are
verified.
- Line 26: Define the forwarded-header allowlist once and reuse it in both
filters: in sources/gsf/src/gsf/client.py:26, rename _FORWARDED_HEADER_NAMES to
the shared public name FORWARDED_HEADER_NAMES while retaining the existing set;
in sources/gsf/src/gsf/register.py:33, remove _TRACE_HEADER_NAMES and import and
use FORWARDED_HEADER_NAMES from the client module.
- Around line 225-232: Update the retry handling around _http_error to honor a
present Retry-After header for 429 responses, clamping the parsed delay to 30
seconds; fall back to exponential backoff with randomized jitter, also capped at
30 seconds, via a _retry_delay helper and the required random import. Pass the
response header into the delay calculation before asyncio.sleep, and update
test_client_retries_rate_limit_then_succeeds to assert the new delay behavior.
- Around line 349-364: Replace str.splitlines() in the SSE parsing loop with
splitting logic that recognizes only CR, LF, and CRLF terminators. Preserve the
existing handling of blank lines, comments, data accumulation, and event parsing
while ensuring U+2028, U+2029, and other non-SSE separators remain inside data
lines.
- Around line 238-246: Restrict the retry branch in the HTTP timeout handling
around the capability request to httpx.ConnectTimeout only, so httpx.ReadTimeout
is immediately converted to the existing GSFError without resending
chat/completions. Add a regression test covering a read timeout and verifying no
retry occurs.

In `@sources/gsf/src/gsf/models.py`:
- Around line 43-51: Update CatalogSearchResponse.coverage to tolerate an
omitted upstream value by assigning a default of 0.0 while preserving its
non-nullable float type and existing ge=0/le=1 constraints, so
_normalize_catalog_search can still return candidates when coverage is missing.

In `@sources/gsf/src/gsf/register.py`:
- Around line 144-153: The query_context tool is registered despite always
returning CAPABILITY_UNAVAILABLE. Remove its registration and associated
schema/description from the function group until the capability is implemented;
if retaining the registration to reserve the name, explicitly document that
intent in query_context’s docstring.
- Around line 109-116: Update both catch-all handlers in
sources/gsf/src/gsf/register.py: lines 109-116 and 135-142, changing the
logger.error calls in the catalog-search and text-to-SQL tool closures to
logger.exception so unexpected failures include traceback and exception details.
No other handler behavior needs to change.
- Around line 76-84: Update _request_trace_headers to emit a debug-level log
containing the caught exception before returning {} from its broad exception
handler; preserve the existing best-effort empty-header fallback and avoid
changing successful header propagation.
- Line 16: Ensure the package containing gsf.register declares a compatible
aiq-agent runtime dependency so the module-level get_auth_token import resolves
during standalone NAT plugin discovery; alternatively, move that import into the
bearer-token authentication path and raise GSFError only when that
authentication is requested.

In `@sources/gsf/tests/test_client.py`:
- Around line 290-307: Add tests covering the remaining _post error paths:
verify repeated 429 responses raise GSFErrorCode.RATE_LIMITED after max_retries
+ 1 attempts, and verify TimeoutException and TransportError are retried then
mapped to TIMEOUT and UPSTREAM_ERROR respectively, including sleep and
response-close behavior. Also add a constructor test for GSFClient confirming
password_auth_email without a password raises ValueError.

In `@sources/gsf/tests/test_models.py`:
- Around line 29-41: Add a test case in
test_catalog_search_response_validates_coverage for constructing
CatalogSearchResponse without the coverage field, using the existing candidate
fixture shape, and assert that the response validates successfully with the
model’s intended default behavior.

In `@sources/gsf/tests/test_register.py`:
- Around line 66-76: Add direct unit coverage for
gsf.register._request_trace_headers without patching it out: provide mixed
metadata headers and assert only allowlisted headers such as traceparent and
x-request-id are returned, excluding authorization and cookie. Also verify it
returns an empty mapping when Context.get is unavailable, while preserving the
existing test setup elsewhere.
🪄 Autofix

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: 400c6372-19c9-47d5-998d-6df61738f9ad

📥 Commits

Reviewing files that changed from the base of the PR and between de423f4 and 9e23c08.

⛔ Files ignored due to path filters (2)
  • mcp/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
  • pyproject.toml
  • scripts/setup.sh
  • sources/gsf/README.md
  • sources/gsf/pyproject.toml
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/src/gsf/client.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/__init__.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/tests/test_register.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Pytest and Coverage
  • GitHub Check: Lint and Hooks
🧰 Additional context used
📓 Path-based instructions (7)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format and lint Python with Ruff using a 120-character line length, Python 3.11 target, rules E/F/W/I/PL/UP, and single-line imports; avoid reformatting unrelated code.
Never print or log secret values, including through tool output or error messages.

**/*.py: Run uv run ruff check . and uv run ruff format --check . for root Python changes.
Run uv run pytest for root project Python changes.

Files:

  • sources/gsf/tests/__init__.py
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Implement new tools and data sources as NeMo Agent Toolkit functions registered with @register_function; configuration schemas must inherit from FunctionBaseConfig.

Files:

  • sources/gsf/tests/__init__.py
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes inside this repository, avoid editing adjacent repositories, and scope changes to the smallest relevant independent package, especially under sources/.
Run the narrowest relevant validation command first and broaden to the full suite only when a change crosses shared boundaries.
Keep pull requests scoped, exclude unrelated files and generated artifacts, never include secrets, and provide validation commands and results.

**/*: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts.
Add or update tests for behavior changes.

Files:

  • sources/gsf/tests/__init__.py
  • pyproject.toml
  • scripts/setup.sh
  • sources/gsf/README.md
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/pyproject.toml
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/gsf/tests/__init__.py
  • sources/gsf/README.md
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/pyproject.toml
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

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

Files:

  • pyproject.toml
.agents/skills/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Use repository maintainer skills from .agents/skills/ for applicable workflows; keep API-consumer skills in skills/ separate because they are not deployed application runtime skills.

Files:

  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
🪛 ast-grep (0.45.0)
sources/gsf/tests/test_client.py

[info] 24-24: use jsonify instead of json.dumps for JSON output
Context: json.dumps({'type': 'result', 'answer': answer})
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (28)
.agents/skills/aiq-configure-workflow/scripts/validate_config.py (2)

122-123: LGTM!


255-255: 🗄️ Data Integrity & Integration

Keep the registry declaration contract consistent with runtime tool names.

The validator admits function-group keys, but the supplied GSF group registers namespaced callable names. Confirm that the data-source registry intentionally consumes group IDs.

  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py#L255-L255: Validate the same identifiers that the registry resolves, or add an explicit group-ID resolution path.
  • sources/gsf/README.md#L44-L45: Keep tools: - gsf only if the registry consumes group IDs; otherwise list the namespaced runtime tools.
scripts/setup.sh (1)

117-117: LGTM!

sources/gsf/README.md (1)

1-27: LGTM!

Also applies to: 29-43, 46-47, 70-80

sources/gsf/tests/__init__.py (1)

1-2: LGTM!

pyproject.toml (1)

213-213: 📐 Maintainability & Code Quality

No lockfile change is needed. uv.lock already contains aiq-gsf as a workspace member, development dependency, editable package, and resolved package with its dependencies.

			> Likely an incorrect or invalid review comment.
sources/gsf/src/gsf/__init__.py (1)

1-10: LGTM!

sources/gsf/src/gsf/errors.py (1)

13-63: LGTM!

sources/gsf/src/gsf/models.py (1)

13-41: LGTM!

Also applies to: 53-124

sources/gsf/tests/conftest.py (1)

7-132: LGTM!

sources/gsf/tests/test_models.py (1)

44-105: LGTM!

sources/gsf/src/gsf/client.py (11)

68-82: LGTM!


105-127: LGTM!

Also applies to: 155-176


195-224: LGTM!

Also applies to: 233-237, 247-260


302-323: LGTM!


325-339: LGTM!


341-348: LGTM!

Also applies to: 365-386


388-419: LGTM!


421-436: LGTM!

Also applies to: 442-467


500-528: LGTM!


530-650: LGTM!


138-153: 🚀 Performance & Scalability

Confirm the question-entity-coverage result-limit contract before changing this payload.

max_results is not sent to GSF. _normalize_catalog_search truncates the returned candidates list locally, so requests can transfer more candidates than requested and may hit max_response_bytes. If the endpoint supports a result-limit field, send request.max_results and retain client-side truncation as a safety net.

sources/gsf/tests/test_client.py (1)

18-34: LGTM!

Also applies to: 37-289, 310-355

sources/gsf/src/gsf/register.py (3)

36-55: LGTM!


58-74: LGTM!


87-108: LGTM!

Also applies to: 117-134, 155-174

sources/gsf/tests/test_register.py (1)

19-65: LGTM!

Also applies to: 79-173

sources/gsf/pyproject.toml (1)

18-25: 📐 Maintainability & Code Quality

Use the existing workspace test configuration. The root pyproject.toml provides pytest, pytest-asyncio, and asyncio_mode = "auto". aiq-gsf is a sources/* workspace member included in the root development group. No package-level test extra or local asyncio configuration is required.

			> Likely an incorrect or invalid review comment.

Comment thread .agents/skills/aiq-configure-workflow/scripts/validate_config.py Outdated
Comment thread sources/gsf/pyproject.toml Outdated
Comment thread sources/gsf/README.md Outdated
Comment thread sources/gsf/README.md
Comment thread sources/gsf/README.md Outdated
Comment thread sources/gsf/src/gsf/register.py
Comment thread sources/gsf/src/gsf/register.py Outdated
Comment thread sources/gsf/tests/test_client.py Outdated
Comment thread sources/gsf/tests/test_models.py
Comment thread sources/gsf/tests/test_register.py
Comment thread sources/gsf/README.md Outdated
@soumilinandi soumilinandi changed the title feat(AIQ-3.0): Add initial version of GSF as a data source feat(aiq-3.0): add initial version of GSF as a data source Aug 7, 2026
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
@soumilinandi
soumilinandi force-pushed the feat/gsf-query-tools branch from 9e23c08 to f0a1a6b Compare August 7, 2026 03:05
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

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

🤖 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 `@sources/gsf/src/gsf/client.py`:
- Around line 411-425: Update the SSE event parsing loop in the client method
containing event_data and _answer_from_event to catch json.JSONDecodeError for
malformed intermediate events, skip those events, and continue reading until a
valid result is found. Preserve strict handling for decodable error/result
events, and add a test using a malformed step event before a valid result that
verifies the SQL is returned.

In `@sources/gsf/src/gsf/register.py`:
- Around line 43-52: The GSF configuration currently uses the shared
FunctionGroup configuration instead of the required registration contract.
Update catalog_search and text_to_sql to use `@register_function` with
FunctionBaseConfig, replacing or separating GSFFunctionGroupConfig as needed
while preserving their existing configuration fields; retain the shared
FunctionGroup design only if an explicit exception is obtained.

In `@sources/gsf/tests/test_client.py`:
- Around line 357-404: The retry tests cover only jitter fallback and not
server-directed delays. Add an async test alongside
test_client_retries_rate_limit_then_succeeds that returns a 429 with a
Retry-After header, retries successfully, and asserts asyncio.sleep is awaited
with the parsed delay clamped to _MAX_RETRY_DELAY_SECONDS (for example, 30.0);
keep the existing deterministic jitter tests unchanged.
🪄 Autofix

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: 39704dea-13f8-407c-afdd-1b7226cc0628

📥 Commits

Reviewing files that changed from the base of the PR and between abf032b and f0a1a6b.

⛔ Files ignored due to path filters (2)
  • mcp/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
  • pyproject.toml
  • scripts/setup.sh
  • sources/gsf/README.md
  • sources/gsf/pyproject.toml
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/src/gsf/client.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/tests/test_models.py
  • sources/gsf/tests/test_register.py
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Lint and Hooks
  • GitHub Check: Pytest and Coverage
  • GitHub Check: Script Validation
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes inside this repository, avoid editing adjacent repositories, and scope changes to the smallest relevant independent package, especially under sources/.
Run the narrowest relevant validation command first and broaden to the full suite only when a change crosses shared boundaries.
Keep pull requests scoped, exclude unrelated files and generated artifacts, never include secrets, and provide validation commands and results.

**/*: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts.
Add or update tests for behavior changes.

Files:

  • scripts/setup.sh
  • sources/gsf/pyproject.toml
  • sources/gsf/tests/test_models.py
  • pyproject.toml
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/README.md
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/gsf/pyproject.toml
  • sources/gsf/tests/test_models.py
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/README.md
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format and lint Python with Ruff using a 120-character line length, Python 3.11 target, rules E/F/W/I/PL/UP, and single-line imports; avoid reformatting unrelated code.
Never print or log secret values, including through tool output or error messages.

**/*.py: Run uv run ruff check . and uv run ruff format --check . for root Python changes.
Run uv run pytest for root project Python changes.

Files:

  • sources/gsf/tests/test_models.py
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Implement new tools and data sources as NeMo Agent Toolkit functions registered with @register_function; configuration schemas must inherit from FunctionBaseConfig.

Files:

  • sources/gsf/tests/test_models.py
  • sources/gsf/src/gsf/__init__.py
  • sources/gsf/tests/conftest.py
  • sources/gsf/src/gsf/models.py
  • sources/gsf/src/gsf/register.py
  • sources/gsf/src/gsf/errors.py
  • sources/gsf/tests/test_register.py
  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
{.github/**,ci/**,.pre-commit-config.yaml,pyproject.toml,uv.lock,mcp/pyproject.toml,mcp/uv.lock}

⚙️ CodeRabbit configuration file

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

Files:

  • pyproject.toml
.agents/skills/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Use repository maintainer skills from .agents/skills/ for applicable workflows; keep API-consumer skills in skills/ separate because they are not deployed application runtime skills.

Files:

  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}

⚙️ CodeRabbit configuration file

{skills/**,.agents/skills/**,.claude/skills/**,.github/skill-eval/**}: Review Agent Skill and skill-eval changes for valid skill metadata, deterministic eval specs, safe handling of
credentials, and clear generated-output boundaries. Do not flag SKILL.md files for missing SPDX headers when the
entrypoint intentionally starts with YAML frontmatter.

Files:

  • .agents/skills/aiq-configure-workflow/scripts/validate_config.py
🪛 ast-grep (0.45.0)
sources/gsf/tests/test_client.py

[info] 28-28: use jsonify instead of json.dumps for JSON output
Context: json.dumps({'type': 'result', 'answer': answer})
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 192-192: use jsonify instead of json.dumps for JSON output
Context: json.dumps({"type": "result", "answer": answer}, ensure_ascii=False)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

sources/gsf/src/gsf/client.py

[info] 371-371: use secrets package over random package
Context: random.random()
Note: [CWE-330] Use of Insufficiently Random Values.

(avoid-random-python)

🔇 Additional comments (26)
sources/gsf/src/gsf/__init__.py (1)

1-11: LGTM!

sources/gsf/src/gsf/errors.py (1)

13-67: LGTM!

sources/gsf/tests/conftest.py (1)

9-134: LGTM!

sources/gsf/tests/test_models.py (1)

18-138: LGTM!

sources/gsf/src/gsf/client.py (11)

28-74: LGTM!


76-119: LGTM!


213-284: LGTM!


286-341: LGTM!


343-372: LGTM!


374-390: LGTM!


441-476: LGTM!


478-526: LGTM!


528-591: LGTM!


593-721: LGTM!


130-169: 🚀 Performance & Scalability

Check whether GSF supports upstream result limits.

catalog_search and text_to_sql apply max_results and max_rows only after _post reads the complete response. A large response can therefore raise RESPONSE_TOO_LARGE before client-side truncation. If the GSF endpoints support result-limit parameters, send the effective limits in the payload and test the API contract.

sources/gsf/tests/test_client.py (4)

20-56: LGTM!


59-232: LGTM!


234-337: LGTM!


408-529: LGTM!

sources/gsf/pyproject.toml (1)

11-25: 📐 Maintainability & Code Quality

The root pyproject.toml provides pytest-asyncio and sets asyncio_mode = "auto" for sources/**/tests. No package-local test dependency is required for root workspace tests.

			> Likely an incorrect or invalid review comment.
.agents/skills/aiq-configure-workflow/scripts/validate_config.py (1)

232-256: Add regression tests for function_groups validation.

This behavior change still needs tests for a valid mapping, invalid list and scalar values, and a registry tool declared through function_groups.

As per coding guidelines, “Add or update tests for behavior changes.”

Source: Coding guidelines

sources/gsf/src/gsf/models.py (1)

1-124: LGTM!

sources/gsf/tests/test_register.py (1)

19-193: LGTM!

scripts/setup.sh (1)

117-117: LGTM!

sources/gsf/README.md (1)

1-81: LGTM!

pyproject.toml (1)

213-213: 🩺 Stability & Availability

The lockfile already includes aiq-gsf and its dependencies. No lockfile update is required.

			> Likely an incorrect or invalid review comment.

Comment thread sources/gsf/src/gsf/client.py
Comment thread sources/gsf/src/gsf/register.py
Comment thread sources/gsf/tests/test_client.py
Signed-off-by: Soumili Nandi <soumilin@nvidia.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.

Caution

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

⚠️ Outside diff range comments (1)
sources/gsf/src/gsf/client.py (1)

364-372: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Parse HTTP-date Retry-After values.

_retry_delay handles only numeric values. HTTP permits Retry-After to contain either delay seconds or an HTTP-date. A valid date currently falls through to jitter, so the client can retry before the server-directed time. (rfc-editor.org)

Parse HTTP dates, calculate the UTC delay, and apply the existing zero and maximum bounds. Add a deterministic test with a known past HTTP-date that asserts a 0.0 delay. As per path instructions: "Review data-source and knowledge-layer changes for ... retry/rate-limit behavior, deterministic tests."

🤖 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 `@sources/gsf/src/gsf/client.py` around lines 364 - 372, The _retry_delay
function currently ignores valid HTTP-date Retry-After values. After numeric
parsing fails, parse the header as an HTTP date, calculate the delay from the
current UTC time, and apply the existing 0.0-to-_MAX_RETRY_DELAY_SECONDS bounds
before returning it; retain jitter fallback for invalid values. Add a
deterministic test using a known past HTTP date that asserts a 0.0 delay.

Source: Path instructions

🤖 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 `@sources/gsf/src/gsf/client.py`:
- Around line 364-372: The _retry_delay function currently ignores valid
HTTP-date Retry-After values. After numeric parsing fails, parse the header as
an HTTP date, calculate the delay from the current UTC time, and apply the
existing 0.0-to-_MAX_RETRY_DELAY_SECONDS bounds before returning it; retain
jitter fallback for invalid values. Add a deterministic test using a known past
HTTP date that asserts a 0.0 delay.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: fb656a97-8112-4e49-8d99-5eab21adf0b7

📥 Commits

Reviewing files that changed from the base of the PR and between f0a1a6b and 9872f90.

📒 Files selected for processing (2)
  • sources/gsf/src/gsf/client.py
  • sources/gsf/tests/test_client.py
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Lint and Hooks
  • GitHub Check: Pytest and Coverage
  • GitHub Check: Script Validation
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format and lint Python with Ruff using a 120-character line length, Python 3.11 target, rules E/F/W/I/PL/UP, and single-line imports; avoid reformatting unrelated code.
Never print or log secret values, including through tool output or error messages.

**/*.py: Run uv run ruff check . and uv run ruff format --check . for root Python changes.
Run uv run pytest for root project Python changes.

Files:

  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Implement new tools and data sources as NeMo Agent Toolkit functions registered with @register_function; configuration schemas must inherit from FunctionBaseConfig.

Files:

  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes inside this repository, avoid editing adjacent repositories, and scope changes to the smallest relevant independent package, especially under sources/.
Run the narrowest relevant validation command first and broaden to the full suite only when a change crosses shared boundaries.
Keep pull requests scoped, exclude unrelated files and generated artifacts, never include secrets, and provide validation commands and results.

**/*: Do not include secrets, credentials, private hostnames, internal-only logs, customer data, or generated local artifacts.
Add or update tests for behavior changes.

Files:

  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/gsf/tests/test_client.py
  • sources/gsf/src/gsf/client.py
🪛 ast-grep (0.45.0)
sources/gsf/tests/test_client.py

[info] 211-211: use jsonify instead of json.dumps for JSON output
Context: json.dumps({"type": "result", "answer": chat_sql_answer})
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (2)
sources/gsf/src/gsf/client.py (1)

40-363: LGTM!

Also applies to: 374-414, 415-420, 421-726

sources/gsf/tests/test_client.py (1)

207-223: LGTM!

Also applies to: 400-419

@soumilinandi

Copy link
Copy Markdown
Contributor Author

/ok to test 9872f90

@cdgamarose-nv cdgamarose-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good to me! Great job!

@cdgamarose-nv
cdgamarose-nv merged commit bb35df3 into NVIDIA-AI-Blueprints:develop Aug 7, 2026
11 checks passed
cdgamarose-nv pushed a commit to cdgamarose-nv/aiq that referenced this pull request Aug 10, 2026
…-Blueprints#427)

* Add GSF structured query tools

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Align GSF adapter with chat completions

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Extend GSF query tools and local authentication

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Validate function group registry references

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Handle GSF prediction PQL response

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Add GSF catalog search capability

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Exclude GSF prose from SQL tool output

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Preserve GSF SQL thought summaries

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Remove unused GSF provenance helper

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Disable unvalidated GSF PQL tool

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Harden GSF integration behavior

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

* Harden GSF SSE response handling

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>

---------

Signed-off-by: Soumili Nandi <soumilin@nvidia.com>
@coderabbitai coderabbitai Bot mentioned this pull request Aug 18, 2026
6 tasks
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