From 5bce725d5b7514f9901cc3ea2d8b00ff1770762c Mon Sep 17 00:00:00 2001 From: Paulo Lacerda Date: Sun, 31 May 2026 08:54:48 -0300 Subject: [PATCH 1/3] chore(deps): pin Azure SDK majors and stamp AgentOps version into generated workflows Two complementary changes that make CI runs reproducible and prevent the class of failure that produced the v0.3.2 stage regression (azure-ai-projects 1.x -> 2.x silently broke prompt-agent staging during a live tutorial recording). pyproject.toml - Add "==X.Y.Z"; editable/dev install -> the existing " @ git+...@main" fallback. PEP 440 aware via packaging.Version. - New __AGENTOPS_INSTALL_SPEC__ template substitution wired into generate_cicd_workflows. - All 10 GitHub Actions workflow templates AND all 10 Azure DevOps pipeline templates rewritten to use __AGENTOPS_INSTALL_SPEC__ in place of the hardcoded "@ git+https://github.com/Azure/agentops.git@main" suffix. - Stale "NOTE: pinned to GitHub main until the next package release" comments removed from 5 templates (the note no longer applies once the install line carries a real version pin). tests/unit/test_cicd.py - 5 new tests cover: clean release -> ==X.Y.Z; PEP 440 post/rc releases -> pin; dev/local segments -> @main fallback; rendered workflows pin to the substituted version end-to-end; dev installs still write the @main fallback into the rendered template. Net effect: a user who runs `agentops workflow generate` against AgentOps 0.3.3 gets workflow files that always install `agentops-accelerator==0.3.3` on every CI run, and `agentops-accelerator` pins the right Azure SDK majors via the new upper bounds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 35 +++++++ pyproject.toml | 30 +++--- src/agentops/services/cicd.py | 37 ++++++- .../azuredevops/agentops-deploy-dev-azd.yml | 2 +- .../azuredevops/agentops-deploy-dev.yml | 2 +- .../azuredevops/agentops-deploy-prod-azd.yml | 2 +- .../azuredevops/agentops-deploy-prod.yml | 2 +- .../agentops-deploy-prompt-agent.yml | 6 +- .../azuredevops/agentops-deploy-qa-azd.yml | 2 +- .../azuredevops/agentops-deploy-qa.yml | 2 +- .../azuredevops/agentops-pr-prompt-agent.yml | 4 +- .../pipelines/azuredevops/agentops-pr.yml | 3 +- .../azuredevops/agentops-watchdog.yml | 2 +- .../workflows/agentops-deploy-dev-azd.yml | 2 +- .../workflows/agentops-deploy-dev.yml | 4 +- .../workflows/agentops-deploy-prod-azd.yml | 2 +- .../workflows/agentops-deploy-prod.yml | 4 +- .../agentops-deploy-prompt-agent.yml | 6 +- .../workflows/agentops-deploy-qa-azd.yml | 2 +- .../workflows/agentops-deploy-qa.yml | 4 +- .../workflows/agentops-pr-prompt-agent.yml | 4 +- .../templates/workflows/agentops-pr.yml | 4 +- .../templates/workflows/agentops-watchdog.yml | 2 +- tests/unit/test_cicd.py | 96 +++++++++++++++++++ 24 files changed, 208 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8df3c1..1e98a15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,41 @@ This format follows [Keep a Changelog](https://keepachangelog.com/) and adheres ## [Unreleased] +### Changed +- **Runtime dependencies now have upper bounds so a future SDK major release + cannot silently break installs.** `pyproject.toml` previously declared every + Azure-SDK dependency with only a lower bound (e.g. `azure-ai-projects>=2.0.1`), + so `pip install agentops-accelerator` could resolve `azure-ai-projects 3.x` + the day after that ships and break the agent-definition serialization (the + exact failure mode that produced the `invalid_payload — Required properties + ["kind"] are not present` regression below). Each Azure SDK dependency + (`azure-ai-projects`, `azure-ai-evaluation`, `azure-identity`, `azure-monitor-*`, + `azure-mgmt-*`) is now constrained to its current major. `pandas`, `fastapi`, + `uvicorn`, `httpx`, and `markdown` are similarly capped to their next major. + `cryptography` is intentionally left unbounded so security patches can flow + through without a coordinated AgentOps release. Lift any of these bounds via + an explicit PR that exercises the new SDK against `tests/`. + +- **`agentops workflow generate` now stamps the installed agentops version + into generated CI/CD templates instead of always installing from + `git+...@main`.** Every generated `agentops-pr.yml`, `agentops-deploy-*.yml`, + `agentops-watchdog.yml` (and their Azure DevOps pipeline equivalents) used to + contain `pip install "agentops-accelerator[...] @ git+https://github.com/Azure/agentops.git@main"`, + with no version pin and a stale "NOTE: pinned to GitHub main until the next + package release" comment. User CI runs were therefore non-reproducible: the + same workflow file pulled different agentops snapshots day to day, which is + how PO's recorded tutorial took a hard SDK regression mid-record. The + generator now writes a literal `==X.Y.Z` pin derived from the agentops version + currently installed on the machine running `agentops workflow generate` — so + a user who generates workflows against AgentOps `0.3.3` always installs + `agentops-accelerator==0.3.3` on every CI run, and `agentops-accelerator` + brings exact-major Azure SDKs along (per the upper bounds above). Editable + installs (versions carrying a local segment like `+gabcdef` or marked + `.devN`) keep the `@main` fallback so contributors testing template changes + still get a resolvable install. Existing user workflows are unaffected until + the user re-runs `agentops workflow generate --force` against a release of + AgentOps that ships this change. + ### Fixed - **Prompt-agent deploy: `stage` no longer fails with `Required properties ["kind"] are not present` against `azure-ai-projects` 2.x.** `_copy_definition` previously called `.copy()` on the typed diff --git a/pyproject.toml b/pyproject.toml index 493b7cc..6974c5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,29 +12,29 @@ dependencies = [ "typer>=0.12,<1.0", "pydantic>=2,<3", "ruamel.yaml>=0.18,<1.0", - "azure-ai-projects>=2.0.1", + "azure-ai-projects>=2.0.1,<3.0", ] license = { file = "LICENSE" } [project.optional-dependencies] mcp = ["mcp>=1.0,<2"] foundry = [ - "azure-ai-evaluation>=1.0", - "azure-identity>=1.17", - "azure-monitor-opentelemetry>=1.6", - "pandas>=2.0", + "azure-ai-evaluation>=1.0,<2.0", + "azure-identity>=1.17,<2.0", + "azure-monitor-opentelemetry>=1.6,<2.0", + "pandas>=2.0,<3.0", ] agent = [ - "fastapi>=0.110", - "uvicorn[standard]>=0.30", - "httpx>=0.27", + "fastapi>=0.110,<1.0", + "uvicorn[standard]>=0.30,<1.0", + "httpx>=0.27,<1.0", "cryptography>=42", - "markdown>=3.6", - "azure-monitor-query>=1.3", - "azure-monitor-opentelemetry>=1.6", - "azure-identity>=1.17", - "azure-mgmt-cognitiveservices>=13.5", - "azure-mgmt-monitor>=6.0", + "markdown>=3.6,<4.0", + "azure-monitor-query>=1.3,<2.0", + "azure-monitor-opentelemetry>=1.6,<2.0", + "azure-identity>=1.17,<2.0", + "azure-mgmt-cognitiveservices>=13.5,<14.0", + "azure-mgmt-monitor>=6.0,<7.0", ] [project.scripts] @@ -66,7 +66,7 @@ where = ["src"] [dependency-groups] dev = [ - "azure-ai-evaluation>=1.0", + "azure-ai-evaluation>=1.0,<2.0", "mypy>=1.19.1", "pre-commit>=4.0", "pytest>=8.0", diff --git a/src/agentops/services/cicd.py b/src/agentops/services/cicd.py index 5b87947..df818a8 100644 --- a/src/agentops/services/cicd.py +++ b/src/agentops/services/cicd.py @@ -27,6 +27,38 @@ _CLOUD_EVAL_CONFIG_NAME = ".agentops.cloud.yaml" _CI_EVAL_OUTPUT = ".agentops/results/latest" +# Git ref used by the dev/editable-install fallback when stamping the agentops +# package version into generated CI/CD templates. Kept here so tests can target +# the same constant without parsing template output. +AGENTOPS_DEV_INSTALL_SPEC = " @ git+https://github.com/Azure/agentops.git@main" + + +def _agentops_install_spec(version: str | None = None) -> str: + """Return the pip version-spec suffix used in generated workflows. + + For a clean public release (e.g. ``0.3.2``, ``0.3.2.post1``, ``0.3.2rc1``) + we pin the exact version so user CI runs are reproducible regardless of + when they are triggered. For editable or dev installs (versions carrying + a local segment such as ``+gabcdef`` or marked as dev-releases) we fall + back to ``@main`` so contributors testing template changes still get a + resolvable install. + """ + + if version is None: + from agentops import __version__ as version # local import to avoid cycles + try: + from packaging.version import InvalidVersion, Version + except ImportError: # pragma: no cover - packaging ships with pip/setuptools + return AGENTOPS_DEV_INSTALL_SPEC + + try: + parsed = Version(version) + except InvalidVersion: + return AGENTOPS_DEV_INSTALL_SPEC + + if parsed.local is not None or parsed.is_devrelease: + return AGENTOPS_DEV_INSTALL_SPEC + return f"=={version}" # CI/CD platforms supported by ``agentops workflow generate``. PLATFORMS: Tuple[str, ...] = ("github", "azure-devops") @@ -648,7 +680,10 @@ def generate_cicd_workflows( continue seen.add(kind) result.kinds.append(kind) - substitutions: dict[str, str] = {"__DOCTOR_GATE__": doctor_gate} + substitutions: dict[str, str] = { + "__DOCTOR_GATE__": doctor_gate, + "__AGENTOPS_INSTALL_SPEC__": _agentops_install_spec(), + } eval_config = ( "${{ inputs.config || 'agentops.yaml' }}" if platform == "github" and kind == "pr" diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml index f542678..fd677fd 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml @@ -74,7 +74,7 @@ __AILZ_PREFLIGHT_COMMAND__ versionSpec: "3.11" - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml index 32cccec..ffb8464 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml @@ -50,7 +50,7 @@ stages: - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml index adf3f12..51a6c7e 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml @@ -74,7 +74,7 @@ __AILZ_PREFLIGHT_COMMAND__ versionSpec: "3.11" - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml index 8f5ecdc..c61d6c6 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml @@ -48,7 +48,7 @@ stages: - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml index 1ecdb2c..46c49d3 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml @@ -48,7 +48,7 @@ stages: scriptLocation: inlineScript inlineScript: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" python -m agentops.pipeline.prompt_deploy stage \ --config "$(AGENTOPS_CONFIG)" \ --environment "$(TARGET_ENVIRONMENT)" \ @@ -93,7 +93,7 @@ stages: - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ @@ -153,7 +153,7 @@ __EVAL_TASKS__ versionSpec: "3.11" - bash: | - python -m pip install "agentops-accelerator @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator__AGENTOPS_INSTALL_SPEC__" python -m agentops.pipeline.prompt_deploy summarize \ --deployment ".agentops/deployments/foundry-agent.json" \ --environment "$(TARGET_ENVIRONMENT)" diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml index c6d576d..84c590a 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml @@ -74,7 +74,7 @@ __AILZ_PREFLIGHT_COMMAND__ versionSpec: "3.11" - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml index 6eaf494..5095bc1 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml @@ -46,7 +46,7 @@ stages: - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml b/src/agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml index 0936dcf..02dfdf0 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml @@ -72,7 +72,7 @@ stages: scriptLocation: inlineScript inlineScript: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" python -m agentops.pipeline.prompt_deploy stage \ --config "$(AGENTOPS_CONFIG)" \ --environment "$(TARGET_ENVIRONMENT)" \ @@ -113,7 +113,7 @@ stages: - bash: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-pr.yml b/src/agentops/templates/pipelines/azuredevops/agentops-pr.yml index 8cf3648..cb19f45 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-pr.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-pr.yml @@ -53,8 +53,7 @@ stages: - bash: | python -m pip install --upgrade pip - # NOTE: pinned to GitHub main until the next package release includes this flow. - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" displayName: Install AgentOps Toolkit __EVAL_TASKS__ diff --git a/src/agentops/templates/pipelines/azuredevops/agentops-watchdog.yml b/src/agentops/templates/pipelines/azuredevops/agentops-watchdog.yml index 186497f..d42062b 100644 --- a/src/agentops/templates/pipelines/azuredevops/agentops-watchdog.yml +++ b/src/agentops/templates/pipelines/azuredevops/agentops-watchdog.yml @@ -65,7 +65,7 @@ stages: scriptLocation: inlineScript inlineScript: | python -m pip install --upgrade pip - python -m pip install "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" agentops doctor --workspace . --out .agentops/agent/report.md \ --severity-fail critical --evidence-pack env: diff --git a/src/agentops/templates/workflows/agentops-deploy-dev-azd.yml b/src/agentops/templates/workflows/agentops-deploy-dev-azd.yml index c217bf6..d49e9d3 100644 --- a/src/agentops/templates/workflows/agentops-deploy-dev-azd.yml +++ b/src/agentops/templates/workflows/agentops-deploy-dev-azd.yml @@ -114,7 +114,7 @@ __AILZ_PREFLIGHT_COMMAND__ - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-deploy-dev.yml b/src/agentops/templates/workflows/agentops-deploy-dev.yml index a598dfc..1e77df2 100644 --- a/src/agentops/templates/workflows/agentops-deploy-dev.yml +++ b/src/agentops/templates/workflows/agentops-deploy-dev.yml @@ -66,9 +66,7 @@ jobs: - name: Install AgentOps Toolkit run: | - # NOTE: pinned to GitHub main until the next package release includes this flow. - # Switch to `uv pip install --system "agentops-accelerator[foundry]"` after release. - uv pip install --system "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-deploy-prod-azd.yml b/src/agentops/templates/workflows/agentops-deploy-prod-azd.yml index cfa9c2d..df0d1bc 100644 --- a/src/agentops/templates/workflows/agentops-deploy-prod-azd.yml +++ b/src/agentops/templates/workflows/agentops-deploy-prod-azd.yml @@ -106,7 +106,7 @@ __AILZ_PREFLIGHT_COMMAND__ enable-cache: false - name: Install AgentOps Toolkit - run: uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + run: uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ - name: Generate release evidence if: always() diff --git a/src/agentops/templates/workflows/agentops-deploy-prod.yml b/src/agentops/templates/workflows/agentops-deploy-prod.yml index 2dd3bb9..039cdad 100644 --- a/src/agentops/templates/workflows/agentops-deploy-prod.yml +++ b/src/agentops/templates/workflows/agentops-deploy-prod.yml @@ -73,9 +73,7 @@ jobs: - name: Install AgentOps Toolkit run: | - # NOTE: pinned to GitHub main until the next package release includes this flow. - # Switch to `uv pip install --system "agentops-accelerator[foundry,agent]"` after release. - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-deploy-prompt-agent.yml b/src/agentops/templates/workflows/agentops-deploy-prompt-agent.yml index 76e724f..9154107 100644 --- a/src/agentops/templates/workflows/agentops-deploy-prompt-agent.yml +++ b/src/agentops/templates/workflows/agentops-deploy-prompt-agent.yml @@ -60,7 +60,7 @@ jobs: - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" - name: Create candidate agent version from prompt_file env: @@ -117,7 +117,7 @@ jobs: - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ @@ -181,7 +181,7 @@ __EVAL_STEPS__ - name: Install AgentOps Toolkit run: | - python -m pip install "agentops-accelerator @ git+https://github.com/Azure/agentops.git@main" + python -m pip install "agentops-accelerator__AGENTOPS_INSTALL_SPEC__" - name: Mark candidate as deployed run: | diff --git a/src/agentops/templates/workflows/agentops-deploy-qa-azd.yml b/src/agentops/templates/workflows/agentops-deploy-qa-azd.yml index d7422c3..af75371 100644 --- a/src/agentops/templates/workflows/agentops-deploy-qa-azd.yml +++ b/src/agentops/templates/workflows/agentops-deploy-qa-azd.yml @@ -109,7 +109,7 @@ __AILZ_PREFLIGHT_COMMAND__ enable-cache: false - name: Install AgentOps Toolkit - run: uv pip install --system "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + run: uv pip install --system "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ - name: Upload AgentOps results if: always() diff --git a/src/agentops/templates/workflows/agentops-deploy-qa.yml b/src/agentops/templates/workflows/agentops-deploy-qa.yml index 2ae78e0..5f437b7 100644 --- a/src/agentops/templates/workflows/agentops-deploy-qa.yml +++ b/src/agentops/templates/workflows/agentops-deploy-qa.yml @@ -66,9 +66,7 @@ jobs: - name: Install AgentOps Toolkit run: | - # NOTE: pinned to GitHub main until the next package release includes this flow. - # Switch to `uv pip install --system "agentops-accelerator[foundry]"` after release. - uv pip install --system "agentops-accelerator[foundry] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-pr-prompt-agent.yml b/src/agentops/templates/workflows/agentops-pr-prompt-agent.yml index 9cbcb04..81e069a 100644 --- a/src/agentops/templates/workflows/agentops-pr-prompt-agent.yml +++ b/src/agentops/templates/workflows/agentops-pr-prompt-agent.yml @@ -76,7 +76,7 @@ jobs: - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" - name: Create candidate agent version from prompt_file env: @@ -133,7 +133,7 @@ jobs: - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-pr.yml b/src/agentops/templates/workflows/agentops-pr.yml index a5d907e..7792974 100644 --- a/src/agentops/templates/workflows/agentops-pr.yml +++ b/src/agentops/templates/workflows/agentops-pr.yml @@ -69,9 +69,7 @@ jobs: - name: Install AgentOps Toolkit run: | - # NOTE: pinned to GitHub main until the next package release includes this flow. - # Switch to `uv pip install --system "agentops-accelerator[foundry,agent]"` after release. - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" __EVAL_STEPS__ diff --git a/src/agentops/templates/workflows/agentops-watchdog.yml b/src/agentops/templates/workflows/agentops-watchdog.yml index 3ce7077..168b973 100644 --- a/src/agentops/templates/workflows/agentops-watchdog.yml +++ b/src/agentops/templates/workflows/agentops-watchdog.yml @@ -62,7 +62,7 @@ jobs: - name: Install AgentOps Toolkit run: | - uv pip install --system "agentops-accelerator[foundry,agent] @ git+https://github.com/Azure/agentops.git@main" + uv pip install --system "agentops-accelerator[foundry,agent]__AGENTOPS_INSTALL_SPEC__" # First run has no prior artifact. Using `pattern:` instead of # `name:` makes actions/download-artifact return success with zero diff --git a/tests/unit/test_cicd.py b/tests/unit/test_cicd.py index 51753d6..6a93572 100644 --- a/tests/unit/test_cicd.py +++ b/tests/unit/test_cicd.py @@ -1007,3 +1007,99 @@ def test_azure_devops_prompt_agent_pr_template_propagates_doctor_gate(tmp_path: assert f"--severity-fail {gate}" in content assert "__DOCTOR_GATE__" not in content + +# --------------------------------------------------------------------------- +# Version-pinning of the AgentOps install spec +# --------------------------------------------------------------------------- + +def test_agentops_install_spec_pins_clean_release() -> None: + from agentops.services.cicd import _agentops_install_spec + + assert _agentops_install_spec("0.3.2") == "==0.3.2" + assert _agentops_install_spec("1.0.0") == "==1.0.0" + + +def test_agentops_install_spec_pins_post_and_rc_releases() -> None: + from agentops.services.cicd import _agentops_install_spec + + # PEP 440 post and rc releases are public-installable and should pin. + assert _agentops_install_spec("0.3.2.post1") == "==0.3.2.post1" + assert _agentops_install_spec("0.4.0rc1") == "==0.4.0rc1" + + +def test_agentops_install_spec_falls_back_for_dev_or_local_installs() -> None: + from agentops.services.cicd import ( + AGENTOPS_DEV_INSTALL_SPEC, + _agentops_install_spec, + ) + + # setuptools-scm dev versions and editable installs must fall back to + # git+main so contributors can still install from their checkout. + assert _agentops_install_spec("0.3.3.dev1") == AGENTOPS_DEV_INSTALL_SPEC + assert _agentops_install_spec("0.3.2+gabcdef") == AGENTOPS_DEV_INSTALL_SPEC + assert _agentops_install_spec("0.0.0-dev") == AGENTOPS_DEV_INSTALL_SPEC + + +def test_workflow_install_lines_pin_to_release_version(tmp_path: Path) -> None: + """Generated workflows must pin agentops to a release version, not @main.""" + + from agentops.services import cicd + + # Force a clean release version so the substitution is deterministic. + original = cicd._agentops_install_spec + cicd._agentops_install_spec = lambda version=None: "==9.9.9" + try: + generate_cicd_workflows(tmp_path, kinds=list(DEFAULT_KINDS), force=True) + generate_cicd_workflows( + tmp_path, + platform="azure-devops", + kinds=list(DEFAULT_KINDS), + force=True, + ) + finally: + cicd._agentops_install_spec = original + + expected_files = ( + tmp_path / _PR_PATH, + tmp_path / _DEV_PATH, + tmp_path / _QA_PATH, + tmp_path / _PROD_PATH, + tmp_path / ".azuredevops/pipelines/agentops-pr.yml", + tmp_path / ".azuredevops/pipelines/agentops-deploy-dev.yml", + tmp_path / ".azuredevops/pipelines/agentops-deploy-qa.yml", + tmp_path / ".azuredevops/pipelines/agentops-deploy-prod.yml", + ) + for path in expected_files: + content = path.read_text(encoding="utf-8") + assert "__AGENTOPS_INSTALL_SPEC__" not in content, ( + f"{path} still has the placeholder" + ) + assert "git+https://github.com/Azure/agentops.git@main" not in content, ( + f"{path} still installs from @main" + ) + assert "agentops-accelerator" in content + assert "==9.9.9" in content, ( + f"{path} does not pin to the substituted release version" + ) + + +def test_workflow_install_lines_fall_back_to_main_for_dev_installs(tmp_path: Path) -> None: + """Editable / setuptools-scm installs keep the git+main fallback.""" + + from agentops.services import cicd + + original = cicd._agentops_install_spec + cicd._agentops_install_spec = ( + lambda version=None: cicd.AGENTOPS_DEV_INSTALL_SPEC + ) + try: + generate_cicd_workflows(tmp_path, kinds=["pr", "dev"], force=True) + finally: + cicd._agentops_install_spec = original + + for path in (tmp_path / _PR_PATH, tmp_path / _DEV_PATH): + content = path.read_text(encoding="utf-8") + assert "__AGENTOPS_INSTALL_SPEC__" not in content + assert " @ git+https://github.com/Azure/agentops.git@main" in content + + From 04a0ea81d3f5a91985309146e1fa4185c70837c5 Mon Sep 17 00:00:00 2001 From: Paulo Lacerda Date: Sun, 31 May 2026 09:10:40 -0300 Subject: [PATCH 2/3] fix(cicd): satisfy mypy str|None narrowing in _agentops_install_spec Use an explicit esolved: str local instead of shadowing the parameter via rom agentops import __version__ as version. mypy 1.x couldn't narrow str | None -> str through the import-rebind, producing 'Argument 1 to `Version` has incompatible type `str | None`'. No behavior change; tests/unit/test_cicd.py still 66/66 green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/agentops/services/cicd.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/agentops/services/cicd.py b/src/agentops/services/cicd.py index df818a8..d9b711d 100644 --- a/src/agentops/services/cicd.py +++ b/src/agentops/services/cicd.py @@ -45,20 +45,24 @@ def _agentops_install_spec(version: str | None = None) -> str: """ if version is None: - from agentops import __version__ as version # local import to avoid cycles + from agentops import __version__ + + resolved = __version__ + else: + resolved = version try: from packaging.version import InvalidVersion, Version except ImportError: # pragma: no cover - packaging ships with pip/setuptools return AGENTOPS_DEV_INSTALL_SPEC try: - parsed = Version(version) + parsed = Version(resolved) except InvalidVersion: return AGENTOPS_DEV_INSTALL_SPEC if parsed.local is not None or parsed.is_devrelease: return AGENTOPS_DEV_INSTALL_SPEC - return f"=={version}" + return f"=={resolved}" # CI/CD platforms supported by ``agentops workflow generate``. PLATFORMS: Tuple[str, ...] = ("github", "azure-devops") From 7eace5d49e41ac9f43f321cad5e8869ef1e2cc97 Mon Sep 17 00:00:00 2001 From: Paulo Lacerda Date: Sun, 31 May 2026 09:16:04 -0300 Subject: [PATCH 3/3] fix(cli): satisfy mypy type-narrowing in run_wizard on_answer callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mypy 1.x cannot narrow the type of a kwargs spread built from a single-field dict literal — it eagerly assumes the value matches the *first* WizardAnswers field's type (Path | None), producing 'Argument 1 to `WizardAnswers` has incompatible type `**dict[str, str]`'. Materialize the partial dict as `dict[str, Any]` so the spread satisfies every field type. Pre-existing failure on develop — unblocking lint for this PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/agentops/cli/app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/agentops/cli/app.py b/src/agentops/cli/app.py index 3eeb6c5..edeff00 100644 --- a/src/agentops/cli/app.py +++ b/src/agentops/cli/app.py @@ -14,7 +14,7 @@ from pathlib import Path from textwrap import wrap from collections.abc import Sequence -from typing import Annotated, Optional +from typing import Annotated, Any, Optional import typer @@ -1554,7 +1554,8 @@ def _prompt(question: str, default: Optional[str]) -> str: } def _on_answer(field_name: str, value: str) -> None: - partial = WizardAnswers(**{field_name: value}) + partial_kwargs: dict[str, Any] = {field_name: value} + partial = WizardAnswers(**partial_kwargs) try: partial_result = apply_answers( workspace,