Publish Python SDK with Codex-pinned versioning (#18996)

**note**: a large chunk of this diff comes from regenerating Python
types after app-server schema changes on `main`.

This is PR 3 of 3 for the Python SDK PyPI publishing split. PR #18862
refreshed the generated SDK surface, and PR #18865 made the runtime
package publishable as `openai-codex-cli-bin`; this final PR makes the
SDK package publishable as `openai-codex-app-server-sdk` and pins both
packages to the same Codex runtime version.

The key idea is that the published SDK version is the Codex runtime
version. That one version now drives the SDK package version, the exact
runtime dependency, the client version reported by the SDK, and the
bootstrap runtime pin. This keeps release-time versioning in one lane
instead of scattering checked-in literals through the package.

## What changed

- Rename the SDK distribution from `codex-app-server-sdk` to
`openai-codex-app-server-sdk` for conflict-free PyPI publishing.
- Use `stage-sdk --codex-version ...` with one Codex version for both
the SDK package version and exact `openai-codex-cli-bin` dependency.
- Preserve hidden legacy `--runtime-version` / `--sdk-version` args only
to reject mismatched versions during staging.
- Map PEP 440 package versions back to Codex release tags for runtime
setup downloads, e.g. `0.116.0a1` -> `rust-v0.116.0-alpha.1`.
- Derive `codex_app_server.__version__`, the default
`AppServerConfig.client_version`, and
`_runtime_setup.pinned_runtime_version()` from the SDK package/project
version instead of hardcoding duplicate version strings.
- Carry the current generated SDK refresh from `main` so
`generate-types` stays clean after recent app-server schema changes.
- Update `sdk/python/uv.lock` for the renamed editable package.

## Validation

- `uv run --extra dev pytest` in `sdk/python` -> 59 passed, 37 skipped.
- Targeted `uv run ruff check` for the touched SDK files.
- `git diff --check`.
- Staged runtime with `--codex-version rust-v0.116.0-alpha.1
--platform-tag macosx_11_0_arm64`.
- Staged SDK with `--codex-version rust-v0.116.0-alpha.1`.
- Built runtime wheel, SDK wheel, and SDK sdist.
- `twine check /tmp/codex-python-pr3-build/dist/*` -> passed.
- Clean venv smoke installed `openai-codex-app-server-sdk==0.116.0a1`
from local dist and pulled `openai-codex-cli-bin==0.116.0a1`.
- Smoke imports passed for `Codex` and `bundled_codex_path()`.
This commit is contained in:
Steve Coffey
2026-04-27 14:28:46 -07:00
committed by GitHub
parent 4ded800374
commit 0f40261e86
16 changed files with 1443 additions and 441 deletions

View File

@@ -2,8 +2,11 @@ from __future__ import annotations
import importlib.resources as resources
import inspect
import tomllib
from pathlib import Path
from typing import Any
import codex_app_server
from codex_app_server import AppServerConfig, RunResult
from codex_app_server.models import InitializeResponse
from codex_app_server.api import AsyncCodex, AsyncThread, Codex, Thread
@@ -37,6 +40,14 @@ def test_root_exports_run_result() -> None:
assert RunResult.__name__ == "RunResult"
def test_package_and_default_client_versions_follow_project_version() -> None:
pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml"
pyproject = tomllib.loads(pyproject_path.read_text())
assert codex_app_server.__version__ == pyproject["project"]["version"]
assert AppServerConfig().client_version == codex_app_server.__version__
def test_package_includes_py_typed_marker() -> None:
marker = resources.files("codex_app_server").joinpath("py.typed")
assert marker.is_file()
@@ -54,6 +65,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"ephemeral",
"model",
"model_provider",
"permission_profile",
"personality",
"sandbox",
"service_name",
@@ -70,6 +82,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"sort_direction",
"sort_key",
"source_kinds",
"use_state_db_only",
],
Codex.thread_resume: [
"approval_policy",
@@ -78,8 +91,10 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"config",
"cwd",
"developer_instructions",
"exclude_turns",
"model",
"model_provider",
"permission_profile",
"personality",
"sandbox",
"service_tier",
@@ -92,8 +107,10 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"cwd",
"developer_instructions",
"ephemeral",
"exclude_turns",
"model",
"model_provider",
"permission_profile",
"sandbox",
"service_tier",
],
@@ -104,6 +121,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"effort",
"model",
"output_schema",
"permission_profile",
"personality",
"sandbox_policy",
"service_tier",
@@ -116,6 +134,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"effort",
"model",
"output_schema",
"permission_profile",
"personality",
"sandbox_policy",
"service_tier",
@@ -131,6 +150,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"ephemeral",
"model",
"model_provider",
"permission_profile",
"personality",
"sandbox",
"service_name",
@@ -147,6 +167,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"sort_direction",
"sort_key",
"source_kinds",
"use_state_db_only",
],
AsyncCodex.thread_resume: [
"approval_policy",
@@ -155,8 +176,10 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"config",
"cwd",
"developer_instructions",
"exclude_turns",
"model",
"model_provider",
"permission_profile",
"personality",
"sandbox",
"service_tier",
@@ -169,8 +192,10 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"cwd",
"developer_instructions",
"ephemeral",
"exclude_turns",
"model",
"model_provider",
"permission_profile",
"sandbox",
"service_tier",
],
@@ -181,6 +206,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"effort",
"model",
"output_schema",
"permission_profile",
"personality",
"sandbox_policy",
"service_tier",
@@ -193,6 +219,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"effort",
"model",
"output_schema",
"permission_profile",
"personality",
"sandbox_policy",
"service_tier",