Skip to content

Commit 1726689

Browse files
fix(packaging): guard agentex-client surface, bump floor, smoke-test wheel install
Harden the 0.13.0 split (agentex-sdk + agentex-client share the agentex.* namespace) against the partial-install break: - Bump the agentex-client floor to >=0.13.0 (first release where it ships separately) so an old client can't satisfy the dep. Kept floor-only: a ceiling would exclude the co-versioned slim (release-please can't bump it). - Sync uv.lock to the 0.13.0 workspace versions (it lagged pyproject at 0.12.0) so frozen installs resolve a client that satisfies the new floor. - Add an import-time guard (agentex.lib) that canaries the agentex-client REST surface and raises a clear, actionable error if a symbol/resource the ADK needs is absent — instead of a cryptic `cannot import name 'Event' from 'agentex.types'`. It does not gate on version (newer clients are additive and must not be rejected); it can't preempt a fully-missing client surface (import agentex fails in the client's own __init__ first) — the wheel smoke covers that. - Add scripts/check-wheel-install (wired into the build CI job): builds both wheels, installs them together into a fresh venv, and imports agentex.lib.adk plus the agentex.types/resources client surface. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 23858df commit 1726689

7 files changed

Lines changed: 90 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ jobs:
6161
# force-include can't build via the sdist-then-wheel default.
6262
run: uv build --all-packages --wheel
6363

64+
- name: Smoke-test wheel install
65+
# Both wheels must install together into one working agentex.* namespace.
66+
run: ./scripts/check-wheel-install
67+
6468
- name: Get GitHub OIDC Token
6569
if: |-
6670
github.repository == 'stainless-sdks/agentex-sdk-python' &&

adk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ readme = "README.md"
1515
dependencies = [
1616
# Co-released in lockstep; floor-only by design — a ceiling would
1717
# eventually exclude the co-versioned slim (release-please can't bump it).
18-
"agentex-client>=0.12.0",
18+
"agentex-client>=0.13.0",
1919
# CLI surface (agentex.lib.cli.*, agentex.lib.sdk.config.*)
2020
"typer>=0.16,<0.17",
2121
"questionary>=2.0.1,<3",

scripts/check-wheel-install

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env bash
2+
# Smoke: agentex-client + agentex-sdk must install together into one working
3+
# agentex.* namespace. Builds + installs in a clean temp dir to avoid stale dist/.
4+
5+
set -euo pipefail
6+
7+
cd "$(dirname "$0")/.."
8+
9+
work="$(mktemp -d)"
10+
echo "==> building both wheels into $work/dist"
11+
uv build --all-packages --wheel --out-dir "$work/dist"
12+
13+
venv="$work/venv"
14+
uv venv "$venv" >/dev/null
15+
echo "==> installing both wheels into a fresh venv"
16+
uv pip install --python "$venv" "$work"/dist/agentex_client-*.whl "$work"/dist/agentex_sdk-*.whl
17+
18+
echo "==> importing the merged namespace from the installed wheels"
19+
"$venv/bin/python" - <<'PY'
20+
import agentex.lib.adk # ADK overlay — ships in agentex-sdk
21+
from agentex.types import Event # client surface — ships in agentex-client
22+
from agentex.resources import states # client surface that "didn't land" in the incident
23+
24+
print("agentex namespace OK:", Event.__name__, states.__name__)
25+
PY

src/agentex/lib/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from agentex.lib._version_guard import verify_client_compatibility
2+
3+
# Fail fast + clearly on a skewed/incomplete agentex-client install.
4+
verify_client_compatibility()

src/agentex/lib/_version_guard.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Fail fast with a clear error on an incomplete agentex-client install instead
2+
of a cryptic `cannot import name ... from agentex.types`."""
3+
4+
from __future__ import annotations
5+
6+
from importlib.metadata import PackageNotFoundError, version
7+
8+
9+
def _installed(package: str) -> str:
10+
try:
11+
return version(package)
12+
except PackageNotFoundError:
13+
return "unknown"
14+
15+
16+
def verify_client_compatibility() -> None:
17+
# Canary on the client REST surface, not the version: newer clients are fine
18+
# (additive); we only fail if a symbol/resource the ADK needs is absent.
19+
try:
20+
from agentex.types import Event as _Event # noqa: F401
21+
from agentex.resources import states as _states # noqa: F401
22+
except (ImportError, AttributeError) as exc:
23+
raise ImportError(
24+
f"agentex-sdk could not import the agentex-client REST surface it "
25+
f"depends on (agentex-sdk={_installed('agentex-sdk')}, "
26+
f"agentex-client={_installed('agentex-client')}). Reinstall both at a "
27+
f"compatible version, e.g. `pip install --force-reinstall agentex-sdk`."
28+
) from exc

tests/lib/test_version_guard.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Tests for the agentex-client compatibility guard (0.13.0 split regression)."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
import agentex.lib._version_guard as guard
8+
9+
10+
def test_passes_when_surface_present() -> None:
11+
guard.verify_client_compatibility() # full client surface installed
12+
13+
14+
def test_newer_client_not_rejected(monkeypatch: pytest.MonkeyPatch) -> None:
15+
# Version is not a gate: a newer client (additive) with the full surface passes.
16+
monkeypatch.setattr(guard, "version", lambda pkg: "0.14.0" if pkg == "agentex-client" else "0.13.0")
17+
guard.verify_client_compatibility()
18+
19+
20+
def test_raises_when_client_surface_incomplete(monkeypatch: pytest.MonkeyPatch) -> None:
21+
import agentex.types
22+
23+
# A partial install missing a needed symbol fails with an actionable error.
24+
monkeypatch.delattr(agentex.types, "Event", raising=False)
25+
with pytest.raises(ImportError, match="could not import the agentex-client REST surface"):
26+
guard.verify_client_compatibility()

uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)