Skip to content
Merged
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
10 changes: 8 additions & 2 deletions .agents/skills/aiq-configure-workflow/scripts/validate_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ def _validate_registry(registry: dict, declared_functions: set[str], errors: lis
for tool in tools:
if tool not in declared_functions:
errors.append(
f"source '{label}' lists tool '{tool}' in its tools:, but '{tool}' is not declared under functions:"
f"source '{label}' lists tool '{tool}' in its tools:, but '{tool}' is not declared under "
"functions: or function_groups:"
)
for bool_field in ("default_enabled", "requires_auth"):
if bool_field in source and not isinstance(source[bool_field], bool):
Expand Down Expand Up @@ -228,6 +229,11 @@ def validate(path: str) -> int:
functions = {}
declared_functions = set(functions.keys())

function_groups = data.get("function_groups", {})
if not isinstance(function_groups, dict):
errors.append("`function_groups:` must be a mapping.")
function_groups = {}

for field, alias in _iter_refs(functions):
if alias not in defined_aliases:
defined = ", ".join(sorted(defined_aliases)) or "none"
Expand All @@ -247,7 +253,7 @@ def validate(path: str) -> int:
if registry is None:
warnings.append("no data_source_registry function found (fine for minimal configs).")
else:
_validate_registry(registry, declared_functions, errors, warnings)
_validate_registry(registry, declared_functions | set(function_groups), errors, warnings)

workflow = data.get("workflow")
for agent_name in REQUIRED_WORKFLOW_AGENTS:
Expand Down
1 change: 1 addition & 0 deletions mcp/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ dev = [
"mypy>=1.5.0",
"dask[distributed]>=2024.1.0",
# Workspace packages for testing
"aiq-gsf",
"google-scholar-paper-search",
"tavily-web-search",
"exa-web-search",
Expand Down Expand Up @@ -259,6 +260,7 @@ exclude = ["mcp"]

[tool.uv.sources]
aiq-agent = { workspace = true }
aiq-gsf = { workspace = true }
google-scholar-paper-search = { workspace = true }
tavily-web-search = { workspace = true }
exa-web-search = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ echo "Benchmarks installed"
# Install data sources
echo ""
echo "Installing data sources..."
"${UV_BIN}" pip install -e ./sources/gsf
"${UV_BIN}" pip install -e ./sources/tavily_web_search
"${UV_BIN}" pip install -e ./sources/exa_web_search
"${UV_BIN}" pip install -e ./sources/nimble_web_search
Expand Down
81 changes: 81 additions & 0 deletions sources/gsf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

# AI-Q GSF source

This package exposes NVIDIA Generative Semantic Fabric (GSF) capabilities as a
NeMo Agent Toolkit function group. The current implementation provides:

- `gsf__text_to_sql`
- `gsf__catalog_search`

PQL client and model groundwork remains internal, but no PQL tool is registered
until its GSF contract and integration behavior are validated.

By default, the function group owns one shared HTTP connection pool and keeps
authentication request-scoped: each tool invocation obtains the current AI-Q
user token and passes it to GSF without storing it on the client.
`GSF_BASE_URL` must point to GSF's auth-aware API origin.

```yaml
function_groups:
gsf:
_type: gsf
base_url: ${GSF_BASE_URL}
include:
- catalog_search
- text_to_sql

functions:
data_sources:
_type: data_source_registry
sources:
- id: gsf
name: "Enterprise Structured Data"
description: >-
Build authorized semantic context and execute bounded structured-data
queries through GSF.
default_enabled: true
requires_auth: true
tools:
- gsf
```

For local development and automated evaluation without an incoming AI-Q user
token, explicitly configure a GSF password session. The credentials must come
from environment variables:

```yaml
function_groups:
gsf:
_type: gsf
Comment thread
coderabbitai[bot] marked this conversation as resolved.
base_url: ${GSF_BASE_URL}
auth:
mode: password
email: ${GSF_EMAIL}
password: ${GSF_PASSWORD}
include:
- catalog_search
- text_to_sql
```

When `auth` is omitted, the existing request-scoped AI-Q user-token flow is
used. Password mode creates one GSF session when the function group starts,
reuses its cookie for local development or evaluation calls, and signs out when
the group closes. The client does not fall back between authentication methods.

Text-to-SQL uses GSF's `/api/chat/completions` SSE endpoint with
`prediction: false`. Its optional AI-Q `database_name` input is sent to GSF as
`target_db`, selecting an existing GSF connection rather than creating one.
The adapter normalizes GSF's current response fields while preserving optional
semantic and benchmarking fields as they become available.
For text-to-SQL, GSF's compatibility prose is discarded; AI-Q consumes the
generated SQL, bounded rows, and any structured semantic provenance instead.
GSF's optional `thoughts` summary is retained as diagnostic context, not as
authoritative evidence.

Catalog search uses `POST /api/question-entity-coverage` and returns entity
coverage plus ranked semantic candidates for DS-agent grounding and routing.
Its optional `database_name` is sent as `target_db`.
25 changes: 25 additions & 0 deletions sources/gsf/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools >= 83"]

[tool.setuptools.packages.find]
where = ["src"]

[project]
name = "aiq-gsf"
version = "0.1.0"
description = "NAT function group for NVIDIA GSF structured-data capabilities"
readme = "README.md"
requires-python = ">=3.11,<3.14"
license = {text = "Apache-2.0"}
dependencies = [
"httpx>=0.27.0,<1",
"nvidia-nat-core==1.8.0",
"pydantic>=2.0.0",
]

[project.entry-points."nat.plugins"]
gsf = "gsf.register"
10 changes: 10 additions & 0 deletions sources/gsf/src/gsf/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""AI-Q integration for NVIDIA Generative Semantic Fabric."""

from .client import GSFClient
from .errors import GSFError
from .errors import GSFErrorCode

__all__ = ["GSFClient", "GSFError", "GSFErrorCode"]
Loading
Loading