diff --git a/deploy/compose/README.md b/deploy/compose/README.md index c841042a8..73cbc4921 100644 --- a/deploy/compose/README.md +++ b/deploy/compose/README.md @@ -108,16 +108,16 @@ cd deploy/compose docker login nvcr.io # Run with pre-built images -BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.0.0 \ -FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0 \ +BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.2.0 \ +FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0 \ docker compose --env-file ../.env -f docker-compose.yaml up -d ``` You can also add these to your `deploy/.env` file: ```bash -BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.0.0 -FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0 +BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.2.0 +FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0 ``` Then run without specifying them on the command line: diff --git a/deploy/compose/docker-compose.yaml b/deploy/compose/docker-compose.yaml index 77335d041..0aab8dd5b 100644 --- a/deploy/compose/docker-compose.yaml +++ b/deploy/compose/docker-compose.yaml @@ -18,8 +18,8 @@ # BUILD_TARGET=release docker compose --env-file ../.env -f docker-compose.yaml up -d --build # # # Use pre-built images from registry (skip --build) -# BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.0.0 \ -# FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0 \ +# BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.2.0 \ +# FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0 \ # docker compose --env-file ../.env -f docker-compose.yaml up -d # # Frontend image: @@ -29,7 +29,7 @@ services: aiq-agent: - image: ${BACKEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-agent:2.0.0} + image: ${BACKEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-agent:2.2.0} build: context: ../.. dockerfile: deploy/Dockerfile @@ -76,7 +76,7 @@ services: restart: unless-stopped frontend: - image: ${FRONTEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0} + image: ${FRONTEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0} build: context: ../../frontends/ui dockerfile: deploy/Dockerfile diff --git a/deploy/helm/README.md b/deploy/helm/README.md index da6120f3d..94822ccd0 100644 --- a/deploy/helm/README.md +++ b/deploy/helm/README.md @@ -31,7 +31,7 @@ All examples use `ns-aiq`. The repository source chart derives every namespaced resource from Helm's `.Release.Namespace`, supplied with `-n`; use a different namespace consistently across Helm, Secrets, `kubectl`, and external identity bindings. The `aiq.namespace.create` value controls whether the source chart renders a Namespace object -and does not override `-n`. The NGC instructions below install published chart 2.0.0. Use +and does not override `-n`. The NGC instructions below install published chart 2.2.0. Use the source chart when you need behavior from the checked-out repository. ## Prerequisites @@ -44,7 +44,7 @@ the source chart when you need behavior from the checked-out repository. ## Install from NGC Helm Repository -This section installs the pre-built chart **aiq2-web** version **2.0.0** from the NGC Helm repository (`https://helm.ngc.nvidia.com/nvidia/blueprint/charts/`). +This section installs the pre-built chart **aiq2-web** version **2.2.0** from the NGC Helm repository (`https://helm.ngc.nvidia.com/nvidia/blueprint/charts/`). ### 1. Create the namespace @@ -78,15 +78,15 @@ kubectl create secret docker-registry ngc-secret -n ns-aiq \ **Pull, verify, then install from local file:** ```bash -helm pull https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.0.0.tgz \ +helm pull https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.2.0.tgz \ --username='$oauthtoken' \ --password= # Verify the chart was pulled correctly -helm show chart aiq2-web-2.0.0.tgz +helm show chart aiq2-web-2.2.0.tgz # Install from the local file -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq --create-namespace \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq --create-namespace \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -99,7 +99,7 @@ helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq --create-namespace \ **Optional — Install directly from the chart URL** (without pulling first): ```bash -helm upgrade --install aiq https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.0.0.tgz \ +helm upgrade --install aiq https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.2.0.tgz \ --username='$oauthtoken' \ --password=$NGC_API_KEY \ -n ns-aiq --create-namespace \ @@ -114,7 +114,7 @@ helm upgrade --install aiq https://helm.ngc.nvidia.com/nvidia/blueprint/charts/a Pass additional `--set` flags to customize the deployment: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -125,7 +125,7 @@ helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ Or supply a custom values file: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ -f custom-values.yaml ``` @@ -135,7 +135,7 @@ helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ To see what values the chart supports before installing: ```bash -helm show values aiq2-web-2.0.0.tgz +helm show values aiq2-web-2.2.0.tgz ``` ### Amazon OpenSearch Serverless @@ -220,10 +220,10 @@ Open [http://localhost:3000](http://localhost:3000) to access the web UI. ### Upgrade -To upgrade an existing release to a newer chart version, pull the new chart archive (same NGC URL pattern with the new version, e.g. `aiq2-web-2.0.1.tgz`) or use the new chart URL for direct install, then run: +To upgrade an existing release to a newer chart version, pull the new chart archive (same NGC URL pattern with the new version, e.g. `aiq2-web-.tgz`) or use the new chart URL for direct install, then run: ```bash -helm upgrade aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -250,7 +250,7 @@ The backend loads a workflow config at startup. Switch configs with `--set`: | `configs/config_web_frag_mcp_auth.yml` | Foundational RAG with optional per-user MCP authentication | ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -281,7 +281,7 @@ aiq: Apply it to either the downloaded chart or a source-chart installation: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ -f aiq-per-user-auth-values.yaml ``` @@ -297,7 +297,7 @@ To use the Foundational RAG (FRAG) config, you need a running NVIDIA RAG Bluepri If the RAG Blueprint is deployed in the same Kubernetes cluster, use internal service DNS: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -314,7 +314,7 @@ Replace `` with the namespace where the RAG Blueprint is deployed If the RAG service is running outside the cluster: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -340,7 +340,7 @@ aiq: ``` ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ -f aiq-frag-values.yaml ``` diff --git a/deploy/helm/deployment-k8s/Chart.yaml b/deploy/helm/deployment-k8s/Chart.yaml index 381c20f91..b619256c9 100644 --- a/deploy/helm/deployment-k8s/Chart.yaml +++ b/deploy/helm/deployment-k8s/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: aiq2-web description: AI-Q - WEB Profile () type: application -version: 2.1.1 -appVersion: '1.0' +version: 2.2.0 +appVersion: '2.2.0' dependencies: - name: aiq version: 0.0.5 diff --git a/deploy/helm/deployment-k8s/charts/aiq-0.0.5.tgz b/deploy/helm/deployment-k8s/charts/aiq-0.0.5.tgz index 22d514e0f..09d80b334 100644 Binary files a/deploy/helm/deployment-k8s/charts/aiq-0.0.5.tgz and b/deploy/helm/deployment-k8s/charts/aiq-0.0.5.tgz differ diff --git a/deploy/helm/deployment-k8s/values.yaml b/deploy/helm/deployment-k8s/values.yaml index 8ba558882..c686523f0 100644 --- a/deploy/helm/deployment-k8s/values.yaml +++ b/deploy/helm/deployment-k8s/values.yaml @@ -37,7 +37,7 @@ aiq: targetMemoryUtilizationPercentage: 80 image: repository: nvcr.io/nvidia/blueprint/aiq-agent - tag: "2.0.0" + tag: "2.2.0" pullPolicy: IfNotPresent imagePullSecrets: [] service: @@ -206,7 +206,7 @@ aiq: targetCPUUtilizationPercentage: 80 image: repository: nvcr.io/nvidia/blueprint/aiq-frontend - tag: "2.0.0" + tag: "2.2.0" pullPolicy: IfNotPresent imagePullSecrets: [] service: diff --git a/deploy/helm/examples/aws-opensearch-serverless-values.yaml b/deploy/helm/examples/aws-opensearch-serverless-values.yaml index 7eb320862..07f6b95bb 100644 --- a/deploy/helm/examples/aws-opensearch-serverless-values.yaml +++ b/deploy/helm/examples/aws-opensearch-serverless-values.yaml @@ -12,7 +12,7 @@ aiq: image: # Override this when testing a custom image that includes unreleased changes. repository: nvcr.io/nvidia/blueprint/aiq-agent - tag: "2.0.0" + tag: "2.2.0" pullPolicy: IfNotPresent imagePullSecrets: - name: ngc-image-pull-secret diff --git a/deploy/helm/helm-charts-k8s/aiq/Chart.yaml b/deploy/helm/helm-charts-k8s/aiq/Chart.yaml index 5c0f19f7d..65e8853f7 100644 --- a/deploy/helm/helm-charts-k8s/aiq/Chart.yaml +++ b/deploy/helm/helm-charts-k8s/aiq/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 2.0.0 +appVersion: 2.2.0 description: AI-Q Helm Chart name: aiq type: application diff --git a/docs/source/deployment/docker-compose.md b/docs/source/deployment/docker-compose.md index 0b0d72c6f..00aba5e86 100644 --- a/docs/source/deployment/docker-compose.md +++ b/docs/source/deployment/docker-compose.md @@ -198,16 +198,16 @@ docker login nvcr.io # Run with pre-built images (no --build flag) cd deploy/compose -BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.0.0 \ -FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0 \ +BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.2.0 \ +FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0 \ docker compose --env-file ../.env -f docker-compose.yaml up -d ``` You can also add the image variables to `deploy/.env` instead of passing them on the command line: ```bash -BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.0.0 -FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.0.0 +BACKEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-agent:2.2.0 +FRONTEND_IMAGE=nvcr.io/nvidia/blueprint/aiq-frontend:2.2.0 ``` ### Release Build diff --git a/docs/source/deployment/kubernetes.md b/docs/source/deployment/kubernetes.md index 6d5cfa282..d67deebd4 100644 --- a/docs/source/deployment/kubernetes.md +++ b/docs/source/deployment/kubernetes.md @@ -64,20 +64,20 @@ kubectl create secret docker-registry ngc-secret -n ns-aiq \ ### Using the NGC Helm chart -Install the pre-built chart **aiq2-web** version **2.0.0** from the NGC Helm repository (`https://helm.ngc.nvidia.com/nvidia/blueprint/charts/`). +Install the pre-built chart **aiq2-web** version **2.2.0** from the NGC Helm repository (`https://helm.ngc.nvidia.com/nvidia/blueprint/charts/`). **1. Pull the chart and install from local file:** ```bash -helm pull https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.0.0.tgz \ +helm pull https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.2.0.tgz \ --username='$oauthtoken' \ --password= # Verify the chart was pulled correctly -helm show chart aiq2-web-2.0.0.tgz +helm show chart aiq2-web-2.2.0.tgz # Install from the local file -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq --create-namespace \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq --create-namespace \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' @@ -88,7 +88,7 @@ Replace `` with your NGC API key (or use `$NGC_API_KEY`). Pref **2. Optional — Install directly from the chart URL** (without pulling first): ```bash -helm upgrade --install aiq https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.0.0.tgz \ +helm upgrade --install aiq https://helm.ngc.nvidia.com/nvidia/blueprint/charts/aiq2-web-2.2.0.tgz \ --username='$oauthtoken' \ --password=$NGC_API_KEY \ -n ns-aiq --create-namespace \ @@ -109,7 +109,7 @@ but you can choose another namespace by replacing it consistently in Helm, `kube Secret creation, and external bindings such as EKS Pod Identity. The `aiq.namespace.create` value controls whether the chart renders a Namespace object; it does not override `-n`. This behavior applies to the repository source chart and does not -change the published NGC 2.0.0 instructions above. +change the published NGC 2.2.0 instructions above. ```bash cd deploy/helm @@ -194,7 +194,7 @@ The backend loads a workflow config at startup. Switch configs with `--set`: | `configs/config_web_frag.yml` | Foundational RAG mode (requires a running RAG service) | ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -212,7 +212,7 @@ To use the Foundational RAG (FRAG) config, you need a running NVIDIA RAG Bluepri If the RAG Blueprint is deployed in the same Kubernetes cluster, use internal service DNS: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -228,7 +228,7 @@ Replace `` with the namespace where the RAG Blueprint is deployed If the RAG service is running outside the cluster: ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' \ @@ -253,7 +253,7 @@ aiq: ``` ```bash -helm upgrade --install aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade --install aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ -f aiq-frag-values.yaml ``` @@ -301,7 +301,7 @@ kubectl rollout restart deployment -n ns-aiq aiq-backend aiq-frontend For NGC Helm chart releases, pull the new chart archive (same NGC URL pattern with the new version) if needed, then run: ```bash -helm upgrade aiq aiq2-web-2.0.0.tgz -n ns-aiq \ +helm upgrade aiq aiq2-web-2.2.0.tgz -n ns-aiq \ --wait --timeout 10m \ --set 'aiq.apps.backend.imagePullSecrets[0].name=ngc-secret' \ --set 'aiq.apps.frontend.imagePullSecrets[0].name=ngc-secret' diff --git a/docs/source/project.json b/docs/source/project.json index da158a78a..b04a97cd5 100644 --- a/docs/source/project.json +++ b/docs/source/project.json @@ -1,4 +1,4 @@ { "name": "NVIDIA AI-Q Blueprint", - "version": "2.2.0-rc1" + "version": "2.2.0" } diff --git a/docs/source/versions1.json b/docs/source/versions1.json index 6185c8440..84d99b234 100644 --- a/docs/source/versions1.json +++ b/docs/source/versions1.json @@ -1,8 +1,8 @@ [ { "preferred": true, - "version": "2.2.0-rc1", - "url": "https://docs.nvidia.com/aiq-blueprint/2.2.0-rc1/" + "version": "2.2.0", + "url": "https://docs.nvidia.com/aiq-blueprint/2.2.0/" }, { "version": "2.1.0", diff --git a/mcp/scripts/check_license_inventory.py b/mcp/scripts/check_license_inventory.py index 3699cd734..0a301c84b 100644 --- a/mcp/scripts/check_license_inventory.py +++ b/mcp/scripts/check_license_inventory.py @@ -30,7 +30,7 @@ } _FORBIDDEN_COMPONENTS = {"maas-sdk", "mos-sdk"} _LOCAL_SOURCE_COMPONENTS = { - ("aiq-agent", "2.0.0"): "../", + ("aiq-agent", "2.2.0"): "../", ("knowledge-layer", "1.0.0"): "../sources/knowledge_layer", ("tavily-web-search", "1.0.0"): "../sources/tavily_web_search", } diff --git a/mcp/tests/test_dependency_compatibility.py b/mcp/tests/test_dependency_compatibility.py index 2c3bc7946..d5a8a3573 100644 --- a/mcp/tests/test_dependency_compatibility.py +++ b/mcp/tests/test_dependency_compatibility.py @@ -27,7 +27,7 @@ def test_runtime_dependency_versions_are_the_validated_compatibility_baseline() assert version("mcp") == "1.28.1" assert version("nvidia-nat") == "1.8.0" assert version("nvidia-nat-core") == "1.8.0" - assert version("aiq-agent") == "2.0.0" + assert version("aiq-agent") == "2.2.0" assert version("cryptography") == "48.0.1" diff --git a/mcp/tests/test_release_checks.py b/mcp/tests/test_release_checks.py index 891d84f6d..753d5f2d2 100644 --- a/mcp/tests/test_release_checks.py +++ b/mcp/tests/test_release_checks.py @@ -181,7 +181,7 @@ def test_sbom_contract_accepts_the_exact_approved_local_component_set() -> None: "specVersion": "1.5", "metadata": {"component": {"name": "aiq-mcp-server", "version": "0.1.0"}}, "components": [ - {"name": "aiq-agent", "version": "2.0.0"}, + {"name": "aiq-agent", "version": "2.2.0"}, {"name": "knowledge-layer", "version": "1.0.0"}, {"name": "tavily-web-search", "version": "1.0.0"}, { @@ -201,7 +201,7 @@ def test_sbom_contract_requires_every_approved_local_component() -> None: "specVersion": "1.5", "metadata": {"component": {"name": "aiq-mcp-server", "version": "0.1.0"}}, "components": [ - {"name": "aiq-agent", "version": "2.0.0"}, + {"name": "aiq-agent", "version": "2.2.0"}, {"name": "knowledge-layer", "version": "1.0.0"}, ], } @@ -246,7 +246,7 @@ def test_sbom_contract_rejects_private_sdk_name_from_public_index() -> None: # representative public-PyPI registry dependency. Each test copies this baseline # and mutates a single entry to exercise one branch of the contract at a time. _APPROVED_LOCK_PACKAGES = [ - ("aiq-agent", "2.0.0", '{ editable = "../" }'), + ("aiq-agent", "2.2.0", '{ editable = "../" }'), ("knowledge-layer", "1.0.0", '{ editable = "../sources/knowledge_layer" }'), ("tavily-web-search", "1.0.0", '{ editable = "../sources/tavily_web_search" }'), ("aiq-mcp-server", "0.1.0", '{ editable = "." }'), @@ -310,7 +310,7 @@ def test_lock_sources_reject_non_editable_local_source(tmp_path: Path, source: s id="extra-unapproved-editable", ), pytest.param( - _without("aiq-agent") + [("aiq-agent", "2.0.0", '{ editable = "../wrong" }')], + _without("aiq-agent") + [("aiq-agent", "2.2.0", '{ editable = "../wrong" }')], id="approved-name-wrong-path", ), pytest.param( @@ -327,7 +327,7 @@ def test_lock_sources_reject_local_set_mismatch(tmp_path: Path, packages: list[t @pytest.mark.parametrize( ("name", "version", "path"), [ - ("aiq-agent", "2.0.0", ".."), + ("aiq-agent", "2.2.0", ".."), ("aiq-mcp-server", "0.1.0", "./"), ], ) diff --git a/mcp/uv.lock b/mcp/uv.lock index de0fc366c..beb6d3b25 100644 --- a/mcp/uv.lock +++ b/mcp/uv.lock @@ -168,7 +168,7 @@ wheels = [ [[package]] name = "aiq-agent" -version = "2.0.0" +version = "2.2.0" source = { editable = "../" } dependencies = [ { name = "aiofiles" }, diff --git a/pyproject.toml b/pyproject.toml index a71f2a472..7ea37fb06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ package-dir = {"" = "src"} [project] name = "aiq-agent" -version = "2.0.0" +version = "2.2.0" description = "NVIDIA AI-Q Blueprint - An enterprise-grade agent for intelligent research assistance" readme = "README.md" requires-python = ">=3.11,<3.14" diff --git a/tests/deploy/test_compose_deployment.py b/tests/deploy/test_compose_deployment.py index 03034c676..4b1462fb6 100644 --- a/tests/deploy/test_compose_deployment.py +++ b/tests/deploy/test_compose_deployment.py @@ -2,8 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 import json +import re import shutil import subprocess +import tomllib from pathlib import Path from typing import Any @@ -14,8 +16,14 @@ REPO_ROOT = Path(__file__).resolve().parents[2] COMPOSE_PATH = REPO_ROOT / "deploy" / "compose" / "docker-compose.yaml" +COMPOSE_README_PATH = REPO_ROOT / "deploy" / "compose" / "README.md" +DOCS_COMPOSE_PATH = REPO_ROOT / "docs" / "source" / "deployment" / "docker-compose.md" +DOCS_PROJECT_PATH = REPO_ROOT / "docs" / "source" / "project.json" +DOCS_VERSIONS_PATH = REPO_ROOT / "docs" / "source" / "versions1.json" +PYPROJECT_PATH = REPO_ROOT / "pyproject.toml" PER_USER_AUTH_COMPOSE_PATH = REPO_ROOT / "deploy" / "compose" / "docker-compose.per-user-auth.yaml" MCP_CONFIG_PATH = REPO_ROOT / "configs" / "config_web_frag_mcp_auth.yml" +EXPECTED_RELEASE_VERSION = "2.2.0" def load_compose() -> dict[str, Any]: @@ -23,6 +31,45 @@ def load_compose() -> dict[str, Any]: return yaml.safe_load(compose_file) +def test_release_version_matches_default_compose_images(): + with PYPROJECT_PATH.open("rb") as pyproject_file: + package_version = tomllib.load(pyproject_file)["project"]["version"] + + compose = load_compose() + + assert package_version == EXPECTED_RELEASE_VERSION + assert compose["services"]["aiq-agent"]["image"] == ( + f"${{BACKEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-agent:{package_version}}}" + ) + assert compose["services"]["frontend"]["image"] == ( + f"${{FRONTEND_IMAGE:-nvcr.io/nvidia/blueprint/aiq-frontend:{package_version}}}" + ) + + expected_backend_image = f"nvcr.io/nvidia/blueprint/aiq-agent:{package_version}" + expected_frontend_image = f"nvcr.io/nvidia/blueprint/aiq-frontend:{package_version}" + for release_path in (COMPOSE_PATH, COMPOSE_README_PATH, DOCS_COMPOSE_PATH): + release_text = release_path.read_text(encoding="utf-8") + backend_images = set(re.findall(r"nvcr\.io/nvidia/blueprint/aiq-agent:[\w.-]+", release_text)) + frontend_images = set(re.findall(r"nvcr\.io/nvidia/blueprint/aiq-frontend:[\w.-]+", release_text)) + assert backend_images == {expected_backend_image} + assert frontend_images == {expected_frontend_image} + + +def test_release_version_matches_published_docs(): + project_metadata = json.loads(DOCS_PROJECT_PATH.read_text(encoding="utf-8")) + published_versions = json.loads(DOCS_VERSIONS_PATH.read_text(encoding="utf-8")) + preferred_versions = [entry for entry in published_versions if entry.get("preferred")] + + assert project_metadata["version"] == EXPECTED_RELEASE_VERSION + assert preferred_versions == [ + { + "preferred": True, + "version": EXPECTED_RELEASE_VERSION, + "url": f"https://docs.nvidia.com/aiq-blueprint/{EXPECTED_RELEASE_VERSION}/", + } + ] + + def test_default_compose_does_not_provision_or_configure_redis(): compose = load_compose() services = compose["services"] diff --git a/tests/deploy/test_helm_deployment_k8s.py b/tests/deploy/test_helm_deployment_k8s.py index 9bc4ae447..e75a0882e 100644 --- a/tests/deploy/test_helm_deployment_k8s.py +++ b/tests/deploy/test_helm_deployment_k8s.py @@ -13,7 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +import re import subprocess +import tarfile +import tomllib from pathlib import Path from typing import Any @@ -21,6 +24,15 @@ REPO_ROOT = Path(__file__).resolve().parents[2] CHART_PATH = REPO_ROOT / "deploy" / "helm" / "deployment-k8s" +CHILD_CHART_DIR = REPO_ROOT / "deploy" / "helm" / "helm-charts-k8s" / "aiq" +CHILD_CHART_PATH = CHILD_CHART_DIR / "Chart.yaml" +PACKAGED_CHILD_CHART_PATH = CHART_PATH / "charts" / "aiq-0.0.5.tgz" +HELM_README_PATH = REPO_ROOT / "deploy" / "helm" / "README.md" +KUBERNETES_DOCS_PATH = REPO_ROOT / "docs" / "source" / "deployment" / "kubernetes.md" +OPENSEARCH_VALUES_PATH = REPO_ROOT / "deploy" / "helm" / "examples" / "aws-opensearch-serverless-values.yaml" +PYPROJECT_PATH = REPO_ROOT / "pyproject.toml" +EXPECTED_RELEASE_VERSION = "2.2.0" +EXPECTED_CHILD_CHART_VERSION = "0.0.5" def render_chart(*extra_args: str, namespace: str = "ns-aiq") -> list[dict[str, Any]]: @@ -43,6 +55,63 @@ def walk_values(value: Any): yield from walk_values(item) +def test_release_version_matches_helm_chart_images_and_docs(): + with PYPROJECT_PATH.open("rb") as pyproject_file: + package_version = tomllib.load(pyproject_file)["project"]["version"] + + parent_chart = yaml.safe_load((CHART_PATH / "Chart.yaml").read_text(encoding="utf-8")) + child_chart = yaml.safe_load(CHILD_CHART_PATH.read_text(encoding="utf-8")) + values = yaml.safe_load((CHART_PATH / "values.yaml").read_text(encoding="utf-8")) + opensearch_values = yaml.safe_load(OPENSEARCH_VALUES_PATH.read_text(encoding="utf-8")) + + with tarfile.open(PACKAGED_CHILD_CHART_PATH, "r:gz") as archive: + packaged_files = {} + for member in archive.getmembers(): + if not member.isfile(): + continue + packaged_file = archive.extractfile(member) + assert packaged_file is not None + relative_path = Path(member.name).relative_to("aiq").as_posix() + packaged_files[relative_path] = packaged_file.read() + + source_files = { + path.relative_to(CHILD_CHART_DIR).as_posix(): path.read_bytes() + for path in CHILD_CHART_DIR.rglob("*") + if path.is_file() + } + packaged_child_chart = yaml.safe_load(packaged_files["Chart.yaml"]) + + assert package_version == EXPECTED_RELEASE_VERSION + assert parent_chart["version"] == EXPECTED_RELEASE_VERSION + assert parent_chart["appVersion"] == EXPECTED_RELEASE_VERSION + assert child_chart["appVersion"] == EXPECTED_RELEASE_VERSION + assert child_chart["version"] == EXPECTED_CHILD_CHART_VERSION + assert packaged_child_chart == child_chart + assert packaged_files.keys() == source_files.keys() + assert {path: content for path, content in packaged_files.items() if path != "Chart.yaml"} == { + path: content for path, content in source_files.items() if path != "Chart.yaml" + } + assert parent_chart["dependencies"][0]["version"] == EXPECTED_CHILD_CHART_VERSION + assert values["aiq"]["apps"]["backend"]["image"]["tag"] == EXPECTED_RELEASE_VERSION + assert values["aiq"]["apps"]["frontend"]["image"]["tag"] == EXPECTED_RELEASE_VERSION + assert opensearch_values["aiq"]["apps"]["backend"]["image"]["tag"] == EXPECTED_RELEASE_VERSION + + rendered_images = { + manifest["metadata"]["name"]: manifest["spec"]["template"]["spec"]["containers"][0]["image"] + for manifest in render_chart() + if manifest.get("kind") == "Deployment" + } + assert rendered_images["aiq-backend"] == f"nvcr.io/nvidia/blueprint/aiq-agent:{EXPECTED_RELEASE_VERSION}" + assert rendered_images["aiq-frontend"] == f"nvcr.io/nvidia/blueprint/aiq-frontend:{EXPECTED_RELEASE_VERSION}" + + expected_chart_archive = f"aiq2-web-{EXPECTED_RELEASE_VERSION}.tgz" + chart_archive_pattern = re.compile(r"aiq2-web-[\w.-]+\.tgz") + for documentation_path in (HELM_README_PATH, KUBERNETES_DOCS_PATH): + documentation = documentation_path.read_text(encoding="utf-8") + assert set(chart_archive_pattern.findall(documentation)) == {expected_chart_archive} + assert f"**aiq2-web** version **{EXPECTED_RELEASE_VERSION}**" in documentation + + def test_default_chart_renders_referenced_configmaps_and_uses_user_supplied_secret(): manifests = render_chart() diff --git a/uv.lock b/uv.lock index c9aa59eea..d668adf48 100644 --- a/uv.lock +++ b/uv.lock @@ -195,7 +195,7 @@ wheels = [ [[package]] name = "aiq-agent" -version = "2.0.0" +version = "2.2.0" source = { editable = "." } dependencies = [ { name = "aiofiles" },