Skip to content

feat(packaging)!: introduce slim agentex-sdk-client + heavy agentex-sdk split#370

Open
max-parke-scale wants to merge 6 commits into
nextfrom
maxparke/agx1-292-prototype-client-split
Open

feat(packaging)!: introduce slim agentex-sdk-client + heavy agentex-sdk split#370
max-parke-scale wants to merge 6 commits into
nextfrom
maxparke/agx1-292-prototype-client-split

Conversation

@max-parke-scale
Copy link
Copy Markdown
Contributor

@max-parke-scale max-parke-scale commented May 26, 2026

Summary

Publishes the existing agentex-sdk wheel as two namespace-sharing packages so REST-only consumers can install just the Stainless REST surface without dragging in the full ADK runtime.

Install command Deps Ships
pip install agentex-sdk-client 6 agentex/{__init__.py, _*.py, _utils/, types/, resources/, protocol/, py.typed}
pip install agentex-sdk 6 (transitive) + 31 ADK only agentex/lib/*; depends on agentex-sdk-client

The two packages contribute disjoint files to the agentex.* namespace. Existing pip install agentex-sdk consumers see no change: heavy depends on slim, so the slim deps install transitively.

Motivating consumer: packages/egp-api-backend hand-rolls a ~600-line JSON-RPC gateway today because it can't import the typed wire shapes without pulling in temporalio, fastapi, claude-agent-sdk, and 28 other deps. With this split + #371 (which moves protocol types to agentex.protocol.*), that gateway can pin agentex-sdk-client and use from agentex.protocol.acp import RPCMethod, CreateTaskParams, ....

Tracking: AGX1-292.

Note on the PR stack

This change was originally drafted as a single large PR (history visible in the force-push). On review it was clearly two distinct concerns, so it's been split:

Reviewing them separately should be much more tractable.

Repo layout after merge

scale-agentex-python/
├── pyproject.toml                # Stainless-managed: agentex-sdk-client
│                                 # 6 deps, requires-python >= 3.11
│                                 # wheel `exclude` keeps lib/ out of the slim wheel
├── src/agentex/                  # shared source tree
│   ├── __init__.py, _*.py, _utils/, types/, resources/   # Stainless-generated
│   ├── protocol/                                          # (from #371)
│   └── lib/                                               # hand-authored ADK overlay
└── adk/                          # hand-authored — preserved via keep_files
    ├── pyproject.toml            # agentex-sdk
    │                             # depends on agentex-sdk-client>=0.11.4,<0.12
    │                             #          + 31 ADK deps
    │                             # requires-python >= 3.12
    │                             # wheel: force-include ../src/agentex/lib → agentex/lib
    └── README.md

src/agentex/lib/ stays where it is — Stainless already preserves it per CONTRIBUTING.md. The slim wheel's [tool.hatch.build.targets.wheel].exclude keeps lib/ out of the slim. The heavy wheel uses hatchling force-include "../src/agentex/lib" = "agentex/lib" to pull lib/ into the heavy. Same source file, two disjoint wheels.

Python-version pins

  • agentex-sdk-client: requires-python = ">= 3.11,<4". Zero 3.12-only imports in the Stainless surface.
  • agentex-sdk: requires-python = ">= 3.12,<4". agentex/lib/* uses from typing import override (3.12+ stdlib) in 19 files. The combined package's prior >= 3.11 pin was de-facto broken on 3.11; this PR aligns the pin with what actually works.

Release / publish wiring

  • bin/publish-pypi: publishes slim before heavy. Heavy depends on slim, so flipping the order means a slim-side failure (token, transient PyPI 5xx, name collision) aborts before we ship a heavy that pins an unreleased slim.
  • bin/check-release-environment: validates both AGENTEX_SDK_CLIENT_PYPI_TOKEN and AGENTEX_PYPI_TOKEN, with legacy PYPI_TOKEN as fallback.
  • .github/workflows/publish-pypi.yml: passes both token secrets to the script.
  • release-please-config.json: two-package mode (. and adk/) with include-component-in-tag = true. Tag scheme changes from v0.11.4agentex-sdk-client-v0.11.4 / agentex-sdk-v0.11.4 — flagged with ! in the title and commit. Any downstream tooling filtering by raw v* tags will need updating.
  • .release-please-manifest.json: seeds adk/ at 0.11.4 so the first release produces matched versions.
  • CI build job: builds both wheels via rye build --wheel (the --wheel flag is important — sdist-then-wheel-from-sdist can't resolve adk's cross-directory force-include from inside an unpacked sdist tarball).

Required maintainer follow-ups before this can ship

  • Stainless dashboard:
    • Add adk/** to keep_files so the ADK overlay persists across codegen.
    • Reduce the dashboard's emitted dep list for root pyproject.toml to the 6 slim-base deps. (See "Risks" below — if this isn't done, every Stainless regen will silently re-add the 31 ADK deps to slim's dependencies = [...].)
  • PyPI: claim the agentex-sdk-client package name; add AGENTEX_SDK_CLIENT_PYPI_TOKEN to repo secrets. agentex-sdk publishing continues using AGENTEX_PYPI_TOKEN from adk/.
  • Verify: after Stainless dashboard config, trigger a Stainless regen and confirm adk/ survives and root pyproject's slim shape isn't clobbered.

Planned follow-up PRs

  • D (in this repo): post-codegen CI guardrail asserting root pyproject.toml's dependencies = [...] is exactly the 6-dep slim set. Catches dashboard drift if Stainless re-adds ADK deps.
  • E (in scaleapi/scaleapi): migrate packages/egp-api-backend from hand-rolled JSON-RPC to typed agentex.protocol.acp shapes; pin agentex-sdk-client. ~600 lines of dict-literal construction become typed model usage.
  • Lockfile regeneration: requirements.lock / requirements-dev.lock need refresh after rye sync against the workspace; not yet committed because the local env doesn't have rye installed. Easy to fix in this PR if reviewers want, or as a fast-follow.
  • README split: the root README.md describes capabilities the slim doesn't ship; deferring to its own PR so this one stays focused on packaging.
  • agentex.__version__ policy: release-please-config.json's extra-files updates only root _version.py, so the runtime __version__ reflects the slim only. Either lockstep-version both (recommended, since they're co-released) or add a separate agentex.lib.__version__.

Verification (local)

# Slim wheel
python -m build --wheel
unzip -p dist/agentex_sdk_client-*.whl '*.dist-info/METADATA' | grep ^Name
# Name: agentex-sdk-client
unzip -p dist/agentex_sdk_client-*.whl '*.dist-info/METADATA' | grep -cE "^Requires-Dist:" | grep -v "extra =="
# 6
unzip -l dist/agentex_sdk_client-*.whl | grep -c "agentex/lib"
# 0  (lib excluded)
unzip -l dist/agentex_sdk_client-*.whl | grep -c "agentex/protocol"
# 3  (from #371)

# Heavy wheel
(cd adk && python -m build --wheel)
unzip -p adk/dist/agentex_sdk-*.whl '*.dist-info/METADATA' | grep "agentex-sdk-client"
# Requires-Dist: agentex-sdk-client<0.12,>=0.11.4
unzip -l adk/dist/agentex_sdk-*.whl | awk '{print $4}' | grep "^agentex/" | grep -v "^agentex/lib"
# (empty — only lib/* in heavy)

# Dual install on Python 3.13
python3.13 -m venv /tmp/c && /tmp/c/bin/pip install \
  dist/agentex_sdk_client-*.whl adk/dist/agentex_sdk-*.whl
/tmp/c/bin/python -c "
from agentex import Agentex                                          # slim
from agentex.protocol.acp import RPCMethod, CreateTaskParams         # slim (from #371)
from agentex.lib.utils.logging import make_logger                    # heavy
from agentex.lib.types.acp import RPCMethod as RM2                   # heavy (shim from #371)
assert RPCMethod is RM2  # shim re-exports canonical
print('OK')
"
# OK

Risks

  • Stainless dashboard dep-list is more load-bearing than the wheel exclude. The slim's [tool.hatch.build.targets.wheel].exclude = ["src/agentex/lib/**"] is a hand-edit to Stainless's emitted file. Manual edits to dependencies = [...] survive Stainless 3-way merge historically (~7 confirmed examples from git log). We're betting the wheel-target exclude survives the same way. If it gets clobbered, the slim wheel would start re-including lib/ and conflict with the heavy on install. Detection: PR D's guardrail check catches it. Mitigation if it happens: re-add manually or move the exclude to the Stainless dashboard if configurable.
  • Tag scheme change. Downstream tooling filtering by v* tags needs to update — flagged with ! in title/commit per Conventional Commits.
  • adk/ sdist support deferred. Wheels publish fine; sdist for adk/ doesn't because rye build's default sdist-then-wheel-from-sdist flow can't resolve the cross-directory force-include. PyPI tolerates wheel-only releases; if reviewers want sdist support, options are (a) configure hatchling to copy ../src/agentex/lib into the sdist, or (b) explicitly disable sdist for adk/.
  • agentex-sdk-client version pin in adk/pyproject.toml is >=0.11.4,<0.12. Release-please doesn't automatically bump this when slim moves; bumping the range is a manual step each minor/major. Comment in the file flags it. A release-please plugin or a small CI substitution rule could automate this in a follow-up.

Greptile Summary

This PR introduces a dual-wheel packaging split: the Stainless-generated REST surface ships as agentex-sdk-client (6 deps, Python ≥ 3.11) and the hand-authored ADK overlay ships as agentex-sdk (31+ deps, Python ≥ 3.12), with the two packages contributing disjoint files to the shared agentex.* namespace. Existing pip install agentex-sdk consumers are unaffected because the heavy package declares agentex-sdk-client as a runtime dependency.

  • pyproject.toml (root): renamed to agentex-sdk-client, 31 ADK deps removed, wheel exclude for agentex/lib/** added to keep the slim disjoint from the heavy.
  • adk/pyproject.toml (new): defines the agentex-sdk wheel with hatchling force-include pulling ../src/agentex/lib into agentex/lib; --wheel flag is load-bearing throughout CI and bin/publish-pypi because the sdist-then-wheel default can't resolve the cross-directory path.
  • Release plumbing: release-please-config.json switches to two-package mode with include-component-in-tag: true; bin/publish-pypi publishes slim before heavy (correct dependency order) and both rye publish calls now carry --skip-existing so the second workflow trigger from the second component tag is idempotent.

Confidence Score: 5/5

Safe to merge; the packaging split is structurally sound, publish order is correct, and --skip-existing handles the dual-trigger from two component tags.

The two previously flagged concerns (missing --wheel on the heavy build and publish idempotency) are both addressed. The remaining findings are advisory: the global extra-files scope could cause version drift if packages ever release independently, and run_test() silently falls back to PyPI wheels when one local wheel is absent. Neither causes a release or correctness failure under the current lockstep-release model.

release-please-config.json (global extra-files scope) and examples/tutorials/run_agent_test.sh (silent wheel fallback in run_test)

Important Files Changed

Filename Overview
pyproject.toml Renamed from agentex-sdk to agentex-sdk-client, stripped 31 ADK deps down to 6 slim deps, added wheel exclude for agentex/lib/**, added rye workspace member for adk/. Correct.
adk/pyproject.toml New file defining the heavy agentex-sdk wheel. hatchling force-include, bypass-selection, and sdist stub are correct for --wheel-only builds. agentex-sdk-client minor-version pin requires manual bumping on each slim minor/major release.
bin/publish-pypi Publishes slim before heavy (correct order), both use --wheel (correct) and --skip-existing (idempotent against double-trigger). Previous review concerns addressed.
release-please-config.json Two-package mode with include-component-in-tag. The global extra-files entry for src/agentex/_version.py will be updated by both package releases; if versions diverge the slim's version may reflect the heavy's version.
.github/workflows/publish-pypi.yml Passes both tokens to bin/publish-pypi with PYPI_TOKEN fallback. With --skip-existing now in place, the double-trigger from two separate component releases is handled gracefully.
examples/tutorials/run_agent_test.sh Updated to require both slim and heavy wheels. start_agent() hard-fails when either is missing; run_test() silently falls back to the PyPI-installed version when one wheel is absent.
bin/check-release-environment Validates both package tokens with PYPI_TOKEN fallback for legacy account-scoped token setups. Logic aligns with the workflow's token injection.
.github/workflows/ci.yml Splits build into two --wheel-only steps, one per package. Correctly replaces rye sync --all-features with ./scripts/bootstrap.
tests/test_function_tool.py Import updated from src.agentex.* path to proper agentex.* package import; type: ignore removed correctly now that the package is properly typed.

Sequence Diagram

sequenceDiagram
    participant RP as release-please
    participant GH as GitHub Actions
    participant Script as bin/publish-pypi
    participant PyPI as PyPI Registry

    RP->>GH: Create release (agentex-sdk-client-vX.Y.Z)
    GH->>Script: trigger publish-pypi.yml
    Script->>Script: rye build --clean --wheel (root)
    Script->>PyPI: rye publish --skip-existing (slim, AGENTEX_SDK_CLIENT_PYPI_TOKEN)
    Script->>Script: "cd adk && rye build --clean --wheel"
    Script->>PyPI: rye publish --skip-existing (heavy, AGENTEX_PYPI_TOKEN)

    RP->>GH: Create release (agentex-sdk-vX.Y.Z)
    GH->>Script: trigger publish-pypi.yml (second run)
    Script->>Script: rye build --clean --wheel (root)
    Script->>PyPI: rye publish --skip-existing (slim, already exists -- skip)
    Script->>Script: "cd adk && rye build --clean --wheel"
    Script->>PyPI: rye publish --skip-existing (heavy, already exists -- skip)
Loading

Comments Outside Diff (1)

  1. .github/workflows/publish-pypi.yml, line 8-9 (link)

    P1 Double-publish failure on separate release events

    With include-component-in-tag: true, release-please creates two separate GitHub releases: agentex-sdk-client-v* and agentex-sdk-v*. Each triggers this workflow independently. Every invocation of bin/publish-pypi publishes both packages unconditionally, so the second triggered run will attempt to re-upload artifacts already present on PyPI. Since rye publish (via twine) exits non-zero on a 409 Conflict and the script runs with set -eux, the second workflow run will fail. Adding --skip-existing to both rye publish calls in bin/publish-pypi (or switching to twine upload --skip-existing dist/*) would make the publish script idempotent and tolerate this re-trigger.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: .github/workflows/publish-pypi.yml
    Line: 8-9
    
    Comment:
    **Double-publish failure on separate release events**
    
    With `include-component-in-tag: true`, release-please creates two separate GitHub releases: `agentex-sdk-client-v*` and `agentex-sdk-v*`. Each triggers this workflow independently. Every invocation of `bin/publish-pypi` publishes *both* packages unconditionally, so the second triggered run will attempt to re-upload artifacts already present on PyPI. Since `rye publish` (via twine) exits non-zero on a 409 Conflict and the script runs with `set -eux`, the second workflow run will fail. Adding `--skip-existing` to both `rye publish` calls in `bin/publish-pypi` (or switching to `twine upload --skip-existing dist/*`) would make the publish script idempotent and tolerate this re-trigger.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Cursor Fix in Claude Code Fix in Codex

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
release-please-config.json:68-70
**Global `extra-files` updates slim's `_version.py` on heavy releases**

The `extra-files` entry for `src/agentex/_version.py` is at the top level of the config, so release-please will apply it to **both** package release PRs — not just the slim's. When `agentex-sdk` cuts a release independently (e.g., a patch-only heavy release), release-please will overwrite `src/agentex/_version.py` with the heavy's version number, causing `from agentex import __version__` (from the slim) to report the heavy's version. Moving `extra-files` under the `"."` package entry scopes it to only slim releases and avoids this drift if versions ever diverge.

### Issue 2 of 2
examples/tutorials/run_agent_test.sh:289-291
**Silent fallback when one wheel is missing in `run_test`**

When `BUILD_CLI=true` and only one of the two wheels is found — for example, the slim wheel glob matches but the heavy wheel lookup returns empty — the `if` guard is false and `pytest_cmd` stays as the plain `uv run ... pytest` invocation with no `--with` flags, running tests against whatever `agentex-sdk` version is already installed in the environment. `start_agent()` correctly hard-fails (`return 1`) in the same scenario. Adding an explicit `else` branch with a warning (or mirroring `start_agent`'s early return) would make the fallback visible rather than silent.

Reviews (7): Last reviewed commit: "chore(release): co-version agentex-sdk (..." | Re-trigger Greptile

@max-parke-scale max-parke-scale force-pushed the maxparke/agx1-292-prototype-client-split branch from 0d7db31 to 4ad75f7 Compare May 26, 2026 23:07
@max-parke-scale max-parke-scale changed the title feat(packaging): introduce slim agentex-sdk-client sibling package feat(packaging): split into slim Stainless-managed client + hand-authored ADK overlay May 26, 2026
max-parke-scale added a commit that referenced this pull request May 26, 2026
…end_path

Follows up the slim/heavy split with the test relocations + dev-install
plumbing that should have been part of the original commit:

- Move tests/lib/* and tests at tests/ root that exercise lib code
  (test_function_tool.py, test_model_utils.py, test_header_forwarding.py)
  into adk/tests/. Tests now live with the code they test. The Path-based
  source references in test_claude_agents_*.py (`_SRC = parents[2] / "src"`)
  resolve correctly to adk/src/ via the new location.

- Fix test_function_tool.py's broken `src.agentex.lib.*` import — switch
  to the installed-package path `agentex.lib.*` so it works against the
  editable install.

- Add `from pkgutil import extend_path; __path__ = extend_path(...)` to
  src/agentex/__init__.py. This is the load-bearing fix for dev workflow:
  without it, two editable installs (slim at root, heavy at adk/) each
  contributing files to `agentex/` get only the first source dir in
  `agentex.__path__`, so `import agentex.lib.*` fails. With it, Python
  discovers both source trees and the namespace merges. Wheel installs
  (production) already worked because both wheels' files land in the same
  site-packages/agentex/ directory.

- scripts/bootstrap: after `rye sync`, also `pip install -e ./adk` so
  agentex-sdk's deps land in the dev venv. agentex-sdk-client is already
  installed via the root sync, so adk's dep on it resolves to the local
  editable install (no PyPI lookup needed).

- pyproject.toml [tool.pytest.ini_options].testpaths includes "adk/tests".
- pyproject.toml [tool.ruff.lint.per-file-ignores] extends test-friendly
  ignores to adk/tests/.
- Drop the rye workspace config — pkgutil.extend_path + explicit pip
  install -e ./adk in bootstrap gives the same dev experience without
  rye-workspace-version-mismatch quirks.
- .github/workflows/ci.yml: lint + test jobs call ./scripts/bootstrap
  instead of `rye sync` directly; build job builds both packages.

Self-review took: I shipped the file move without running the test suite
locally — that's why CI broke on PR #370. Mea culpa. The functional design
is correct; the rollout was sloppy. Verified locally:
- `ruff check .` → All checks passed
- `pytest --collect-only adk/tests/` → 100+ tests collect cleanly
- `pytest adk/tests/test_function_tool.py` → 10 passed
- Dev install (`pip install -e .` + `pip install -e ./adk`):
  `from agentex import Agentex` and `from agentex.lib.* import …` both work

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@max-parke-scale max-parke-scale force-pushed the maxparke/agx1-292-prototype-client-split branch from 2a08eeb to 3a95482 Compare May 27, 2026 03:58
@max-parke-scale max-parke-scale changed the base branch from next to maxparke/agx1-292-promote-protocol-types May 27, 2026 03:58
@max-parke-scale max-parke-scale changed the title feat(packaging): split into slim Stainless-managed client + hand-authored ADK overlay feat(packaging)!: introduce slim agentex-sdk-client + heavy agentex-sdk split May 27, 2026
Base automatically changed from maxparke/agx1-292-promote-protocol-types to next May 27, 2026 15:36
@max-parke-scale max-parke-scale marked this pull request as ready for review May 27, 2026 15:37
@max-parke-scale max-parke-scale force-pushed the maxparke/agx1-292-prototype-client-split branch from 1198bf9 to da5b8f0 Compare May 27, 2026 15:37
Comment thread bin/publish-pypi Outdated
Comment thread adk/pyproject.toml
@max-parke-scale
Copy link
Copy Markdown
Contributor Author

Fixed in cdb3a48:

  • bin/publish-pypi: added --wheel to both slim and heavy rye build --clean so neither falls into rye's sdist-then-wheel-from-sdist default (which silently produces an empty heavy wheel because the unpacked sdist can't resolve adk/'s ../src/agentex/lib force-include).
  • adk/pyproject.toml: dropped the malformed "/../src/agentex/lib/**" sdist entry; sdist support for the dual-package layout is deferred (CI + publish-pypi are wheel-only).

Verified locally: both wheels build with uvx pyproject-build --wheel and have disjoint contents (slim has 0 agentex/lib/* files; heavy has 347 lib/* files + no top-level client surface).

@greptile review

🤖 — posted via Claude Code

@max-parke-scale
Copy link
Copy Markdown
Contributor Author

@greptile review

@max-parke-scale max-parke-scale force-pushed the maxparke/agx1-292-prototype-client-split branch from a1617e5 to 69316be Compare May 29, 2026 15:18
max-parke-scale and others added 6 commits May 29, 2026 16:05
…dk 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>
…wheels to uv

The tutorial test workflow boots an agentex agent via `uv run --with <wheel>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
@max-parke-scale max-parke-scale force-pushed the maxparke/agx1-292-prototype-client-split branch from 69316be to 820c3be Compare May 29, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant