Skip to content

Commit 3a95482

Browse files
feat(packaging)!: introduce slim agentex-sdk-client + heavy agentex-sdk split
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) <noreply@anthropic.com>
1 parent 7590970 commit 3a95482

10 files changed

Lines changed: 232 additions & 52 deletions

.github/workflows/ci.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
RYE_INSTALL_OPTION: '--yes'
3333

3434
- name: Install dependencies
35-
run: rye sync --all-features
35+
run: ./scripts/bootstrap
3636

3737
- name: Run lints
3838
run: ./scripts/lint
@@ -57,10 +57,19 @@ jobs:
5757
RYE_INSTALL_OPTION: '--yes'
5858

5959
- name: Install dependencies
60-
run: rye sync --all-features
60+
run: ./scripts/bootstrap
61+
62+
- name: Run build (slim agentex-sdk-client)
63+
# --wheel only: avoid the sdist intermediate step, which would
64+
# otherwise force the heavy build below to resolve cross-directory
65+
# paths from inside a sdist tarball.
66+
run: rye build --wheel
6167

62-
- name: Run build
63-
run: rye build
68+
- name: Run build (ADK overlay agentex-sdk)
69+
# Heavy wheel uses hatchling force-include to pull
70+
# ../src/agentex/lib into agentex/lib. Building --wheel directly
71+
# (vs sdist-then-wheel) keeps the relative path resolvable.
72+
run: (cd adk && rye build --wheel)
6473

6574
- name: Get GitHub OIDC Token
6675
if: |-

.github/workflows/publish-pypi.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,11 @@ jobs:
2828
run: |
2929
bash ./bin/publish-pypi
3030
env:
31+
# Heavy `agentex-sdk` package token (existing PyPI name).
32+
AGENTEX_PYPI_TOKEN: ${{ secrets.AGENTEX_PYPI_TOKEN }}
33+
# Slim `agentex-sdk-client` package token (new PyPI name; needs
34+
# to be added to repo secrets when the slim is registered).
35+
AGENTEX_SDK_CLIENT_PYPI_TOKEN: ${{ secrets.AGENTEX_SDK_CLIENT_PYPI_TOKEN }}
36+
# Back-compat fallback — used by bin/publish-pypi when the
37+
# dedicated tokens above are unset.
3138
PYPI_TOKEN: ${{ secrets.AGENTEX_PYPI_TOKEN || secrets.PYPI_TOKEN }}

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
".": "0.11.4"
2+
".": "0.11.4",
3+
"adk": "0.11.4"
34
}

adk/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# agentex-sdk
2+
3+
The Agent Development Kit (ADK) overlay for the Agentex API.
4+
5+
## What's in here
6+
7+
This package ships everything under `agentex.lib.*`:
8+
9+
- **ACP server** (`agentex.lib.sdk.fastacp`) — FastAPI-based agent control plane.
10+
- **Temporal workflows** (`agentex.lib.core.temporal`) — durable agent execution.
11+
- **CLI** (`agentex.lib.cli`) — `agentex init`, `agentex run`, deploy helpers.
12+
- **LLM provider integrations** (`agentex.lib.adk.providers`, `agentex.lib.core.temporal.plugins`) — OpenAI Agents, Claude Agent SDK, pydantic-ai, langgraph, litellm.
13+
- **Observability** (`agentex.lib.core.tracing`, `agentex.lib.core.observability`) — SGP, Datadog, OpenTelemetry tracing processors.
14+
15+
## Installation
16+
17+
```sh
18+
pip install agentex-sdk
19+
```
20+
21+
This automatically pulls in [`agentex-sdk-client`](../) (the slim Stainless-generated REST client) so `from agentex import Agentex, AsyncAgentex` works the same as before.
22+
23+
## When to use this vs `agentex-sdk-client`
24+
25+
- **`agentex-sdk`** — you're authoring agents. Pulls everything: ACP server, Temporal, MCP, LLM providers, observability, CLI. ~37 deps.
26+
- **`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.
27+
28+
The two packages contribute disjoint files to the `agentex.*` namespace — `agentex/lib/*` ships only from `agentex-sdk`.
29+
30+
## Repo layout
31+
32+
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.

adk/pyproject.toml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
[project]
2+
# Hand-authored ADK overlay for agentex. This package contributes only
3+
# `agentex/lib/*` to the agentex.* namespace; the REST client surface
4+
# (agentex/{__init__.py, _*.py, types/, resources/}) ships from the slim
5+
# sibling package `agentex-sdk-client` which is pinned as a runtime dep.
6+
#
7+
# This entire `adk/` directory must be preserved across Stainless codegen
8+
# via `keep_files: ["adk/**"]` in the Stainless dashboard config.
9+
name = "agentex-sdk"
10+
version = "0.11.4"
11+
description = "Agent Development Kit (ADK) overlay for the Agentex API — FastACP server, Temporal workflows, LLM provider integrations, observability"
12+
license = "Apache-2.0"
13+
authors = [
14+
{ name = "Agentex", email = "roxanne.farhad@scale.com" },
15+
]
16+
readme = "README.md"
17+
18+
dependencies = [
19+
# Lockstep with this package's own version — both are co-released. The
20+
# heavy package imports from `agentex.types.*` and `agentex.protocol.*`
21+
# which ship from the slim, so a slim bump that drops/renames anything
22+
# imported here would silently break heavy. Bump this range whenever the
23+
# slim's major/minor changes.
24+
"agentex-sdk-client>=0.11.4,<0.12",
25+
# CLI surface (agentex.lib.cli.*, agentex.lib.sdk.config.*)
26+
"typer>=0.16,<0.17",
27+
"questionary>=2.0.1,<3",
28+
"rich>=13.9.2,<14",
29+
"yaspin>=3.1.0",
30+
"pyyaml>=6.0.2,<7",
31+
"python-on-whales>=0.73.0,<0.74",
32+
"kubernetes>=25.0.0,<36.0.0",
33+
"jsonref>=1.1.0,<2",
34+
"jsonschema>=4.23.0,<5",
35+
"jinja2>=3.1.3,<4",
36+
"watchfiles>=0.24.0,<1.0",
37+
# ACP server (FastAPI app surface)
38+
"fastapi>=0.115.0",
39+
"starlette>=0.49.1",
40+
"uvicorn>=0.31.1",
41+
"aiohttp>=3.10.10,<4",
42+
# Temporal workflows
43+
"temporalio>=1.26.0,<2",
44+
"cloudpickle>=3.1.1",
45+
# Async streaming infra
46+
"redis>=5.2.0,<8",
47+
# LLM provider integrations
48+
"litellm>=1.83.7,<2",
49+
"openai-agents==0.14.1",
50+
"openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711)
51+
"claude-agent-sdk>=0.1.0",
52+
"pydantic-ai-slim>=1.0,<2",
53+
"langgraph-checkpoint>=2.0.0",
54+
"scale-gp>=0.1.0a59",
55+
"scale-gp-beta>=0.2.0",
56+
"mcp>=1.4.1",
57+
# Observability
58+
"ddtrace>=3.13.0",
59+
"opentelemetry-api>=1.20.0",
60+
"opentelemetry-sdk>=1.20.0",
61+
"json_log_formatter>=1.1.1",
62+
]
63+
64+
# agentex/lib/* uses `from typing import override` (3.12+) in 19 files.
65+
# The slim agentex-sdk-client keeps 3.11 support.
66+
requires-python = ">= 3.12,<4"
67+
classifiers = [
68+
"Typing :: Typed",
69+
"Intended Audience :: Developers",
70+
"Programming Language :: Python :: 3.12",
71+
"Programming Language :: Python :: 3.13",
72+
"Programming Language :: Python :: 3.14",
73+
"Operating System :: OS Independent",
74+
"Topic :: Software Development :: Libraries :: Python Modules",
75+
"License :: OSI Approved :: Apache Software License",
76+
]
77+
78+
[project.urls]
79+
Homepage = "https://github.com/scaleapi/scale-agentex-python"
80+
Repository = "https://github.com/scaleapi/scale-agentex-python"
81+
82+
[project.scripts]
83+
agentex = "agentex.lib.cli.commands.main:app"
84+
85+
[build-system]
86+
requires = ["hatchling"]
87+
build-backend = "hatchling.build"
88+
89+
# Ship only agentex/lib/*, pulled in from the parent repo's `src/agentex/lib`
90+
# tree. The rest of agentex.* (the Stainless-generated client) ships from the
91+
# sibling agentex-sdk-client package, which this package pins as a runtime dep.
92+
# Stainless explicitly preserves `src/agentex/lib/` across codegen (per
93+
# CONTRIBUTING.md), so it's safe to keep the source where it is.
94+
[tool.hatch.build.targets.wheel]
95+
bypass-selection = true
96+
97+
[tool.hatch.build.targets.wheel.force-include]
98+
"../src/agentex/lib" = "agentex/lib"
99+
100+
[tool.hatch.build.targets.sdist]
101+
include = [
102+
"/pyproject.toml",
103+
"/README.md",
104+
"/../src/agentex/lib/**",
105+
]

bin/check-release-environment

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
#!/usr/bin/env bash
22

3+
# This script is run by Release Doctor to validate the release environment.
4+
# After the dual-package split (slim agentex-sdk-client + heavy agentex-sdk),
5+
# both PyPI tokens must be present — one for each package name. If only
6+
# PYPI_TOKEN is set, fall back to using it for both (back-compat for legacy
7+
# single-token setups, which forces an account-scoped token).
8+
39
errors=()
410

5-
if [ -z "${PYPI_TOKEN}" ]; then
6-
errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
11+
# Heavy `agentex-sdk` token (existing PyPI name).
12+
if [ -z "${AGENTEX_PYPI_TOKEN}" ] && [ -z "${PYPI_TOKEN}" ]; then
13+
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.")
14+
fi
15+
16+
# Slim `agentex-sdk-client` token (new PyPI name).
17+
if [ -z "${AGENTEX_SDK_CLIENT_PYPI_TOKEN}" ] && [ -z "${PYPI_TOKEN}" ]; then
18+
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.")
719
fi
820

921
lenErrors=${#errors[@]}

bin/publish-pypi

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,34 @@
11
#!/usr/bin/env bash
22

3+
# Publish both the Stainless-managed slim `agentex-sdk-client` package (built
4+
# from this repo's root) and the hand-authored `agentex-sdk` ADK overlay
5+
# (built from adk/). The two packages contribute disjoint files to the same
6+
# `agentex.*` namespace; `agentex-sdk` pins `agentex-sdk-client` as a runtime
7+
# dep so installing `agentex-sdk` transitively pulls in the slim client.
8+
#
9+
# Publish ORDER matters: slim first, then heavy. Heavy's dep on slim means
10+
# anyone installing `agentex-sdk` hits resolver failure if slim hasn't shipped
11+
# yet. Failing the slim publish before the heavy gives us a chance to abort
12+
# without leaving an inconsistent registry state.
13+
#
14+
# Tokens:
15+
# - $AGENTEX_SDK_CLIENT_PYPI_TOKEN — auths publishing the slim client
16+
# - $AGENTEX_PYPI_TOKEN (alias $PYPI_TOKEN for back-compat) — auths
17+
# publishing the heavy ADK overlay (which continues to claim the
18+
# `agentex-sdk` name on PyPI)
19+
320
set -eux
21+
22+
# Slim Stainless-managed client (root) — new `agentex-sdk-client` PyPI name.
423
mkdir -p dist
524
rye build --clean
6-
rye publish --yes --token=$PYPI_TOKEN
25+
rye publish --yes --token="${AGENTEX_SDK_CLIENT_PYPI_TOKEN:-$PYPI_TOKEN}"
26+
27+
# Heavy ADK overlay (adk/) — keeps the existing `agentex-sdk` PyPI name.
28+
# Pins `agentex-sdk-client` which the previous step just published.
29+
(
30+
cd adk
31+
mkdir -p dist
32+
rye build --clean
33+
rye publish --yes --token="${AGENTEX_PYPI_TOKEN:-$PYPI_TOKEN}"
34+
)

pyproject.toml

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
[project]
2-
name = "agentex-sdk"
2+
# This is the Stainless-generated REST client. The hand-authored ADK
3+
# overlay (formerly `src/agentex/lib/*`) now lives in `adk/` and ships
4+
# as the sibling `agentex-sdk` package — see `adk/pyproject.toml`.
5+
#
6+
# Stainless dashboard config must:
7+
# - Rename `package_name` from `agentex-sdk` to `agentex-sdk-client`
8+
# - Reduce the dep list to the 6 bare-client deps below
9+
# - Add `adk/**` to `keep_files` so the ADK overlay persists across codegen
10+
name = "agentex-sdk-client"
311
version = "0.11.4"
4-
description = "The official Python library for the agentex API"
12+
description = "The official Python REST client for the Agentex API"
513
dynamic = ["readme"]
614
license = "Apache-2.0"
715
authors = [
@@ -15,37 +23,6 @@ dependencies = [
1523
"anyio>=3.5.0, <5",
1624
"distro>=1.7.0, <2",
1725
"sniffio",
18-
"typer>=0.16,<0.17",
19-
"questionary>=2.0.1,<3",
20-
"rich>=13.9.2,<14",
21-
"fastapi>=0.115.0",
22-
"starlette>=0.49.1",
23-
"uvicorn>=0.31.1",
24-
"watchfiles>=0.24.0,<1.0",
25-
"python-on-whales>=0.73.0,<0.74",
26-
"pyyaml>=6.0.2,<7",
27-
"jsonschema>=4.23.0,<5",
28-
"jsonref>=1.1.0,<2",
29-
"temporalio>=1.26.0,<2",
30-
"aiohttp>=3.10.10,<4",
31-
"redis>=5.2.0,<8",
32-
"litellm>=1.83.7,<2",
33-
"kubernetes>=25.0.0,<36.0.0",
34-
"jinja2>=3.1.3,<4",
35-
"mcp>=1.4.1",
36-
"scale-gp>=0.1.0a59",
37-
"openai-agents==0.14.1",
38-
"pydantic-ai-slim>=1.0,<2",
39-
"json_log_formatter>=1.1.1",
40-
"scale-gp-beta>=0.2.0",
41-
"openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711)
42-
"cloudpickle>=3.1.1",
43-
"ddtrace>=3.13.0",
44-
"yaspin>=3.1.0",
45-
"claude-agent-sdk>=0.1.0",
46-
"langgraph-checkpoint>=2.0.0",
47-
"opentelemetry-sdk>=1.20.0",
48-
"opentelemetry-api>=1.20.0",
4926
]
5027

5128
requires-python = ">= 3.11,<4"
@@ -75,8 +52,14 @@ dev = [
7552
"ruff>=0.3.4",
7653
]
7754

78-
[project.scripts]
79-
agentex = "agentex.lib.cli.commands.main:app"
55+
# The `agentex` CLI entry point ships from the ADK package — see
56+
# `adk/pyproject.toml`. The slim client has no CLI surface.
57+
58+
[tool.rye.workspace]
59+
# `rye sync` from the root installs both this slim package and the ADK
60+
# overlay editably. `src/agentex/lib/` is shared source: the slim wheel
61+
# excludes it; the heavy wheel includes it via hatchling force-include.
62+
members = ["adk"]
8063

8164
[tool.rye]
8265
managed = true
@@ -144,13 +127,11 @@ include = [
144127

145128
[tool.hatch.build.targets.wheel]
146129
packages = ["src/agentex"]
147-
# Don't ship internal test files in the wheel. `lib/cli/templates/**/test_agent.py.j2`
148-
# is intentionally kept — those render into user projects.
130+
# agentex/lib/* ships from the sibling agentex-sdk package (see adk/pyproject.toml).
131+
# Excluding it here keeps the slim wheel disjoint from the heavy wheel so both
132+
# can install into the same site-packages/agentex/ without file conflicts.
149133
exclude = [
150-
"src/agentex/lib/**/tests/**",
151-
"src/agentex/lib/**/test_*.py",
152-
"src/agentex/lib/**/conftest.py",
153-
"src/agentex/lib/**/pytest.ini",
134+
"src/agentex/lib/**",
154135
]
155136

156137
[tool.hatch.build.targets.sdist]

release-please-config.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
{
22
"packages": {
3-
".": {}
3+
".": {
4+
"component": "agentex-sdk-client"
5+
},
6+
"adk": {
7+
"component": "agentex-sdk"
8+
}
49
},
510
"$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json",
611
"include-v-in-tag": true,
7-
"include-component-in-tag": false,
12+
"include-component-in-tag": true,
813
"versioning": "prerelease",
914
"prerelease": true,
1015
"bump-minor-pre-major": true,

tests/test_function_tool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77
from pydantic import ValidationError
88

9-
from src.agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # type: ignore[import-untyped]
9+
from agentex.lib.core.temporal.activities.adk.providers.openai_activities import (
1010
FunctionTool,
1111
)
1212

0 commit comments

Comments
 (0)