mirror of
https://github.com/openai/codex.git
synced 2026-03-14 18:06:30 +03:00
Compare commits
4 Commits
dev/friel/
...
dev/steve/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d881fb590 | ||
|
|
2fc0ca1ec8 | ||
|
|
c9230a345d | ||
|
|
a0b88262da |
35
.github/workflows/rust-release-windows.yml
vendored
35
.github/workflows/rust-release-windows.yml
vendored
@@ -181,6 +181,41 @@ jobs:
|
||||
account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
||||
certificate-profile-name: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }}
|
||||
|
||||
- name: Setup Python for runtime packaging
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Build Python runtime wheel
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.ref_name }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version="${RELEASE_TAG#rust-v}"
|
||||
staging_dir="${RUNNER_TEMP}/codex-cli-bin-${TARGET}"
|
||||
out_dir="${GITHUB_WORKSPACE}/dist-python/${TARGET}"
|
||||
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install build hatchling
|
||||
|
||||
python sdk/python/scripts/update_sdk_artifacts.py \
|
||||
stage-runtime \
|
||||
"${staging_dir}" \
|
||||
"codex-rs/target/${TARGET}/release/codex.exe" \
|
||||
--runtime-version "${version}"
|
||||
|
||||
python -m build --wheel --outdir "${out_dir}" "${staging_dir}"
|
||||
|
||||
- name: Upload Python runtime wheel
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-runtime-${{ matrix.target }}
|
||||
path: dist-python/${{ matrix.target }}/*
|
||||
|
||||
- name: Stage artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
220
.github/workflows/rust-release.yml
vendored
220
.github/workflows/rust-release.yml
vendored
@@ -302,6 +302,41 @@ jobs:
|
||||
apple-notarization-key-id: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
|
||||
apple-notarization-issuer-id: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
|
||||
|
||||
- name: Setup Python for runtime packaging
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Build Python runtime wheel
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.ref_name }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version="${RELEASE_TAG#rust-v}"
|
||||
staging_dir="${RUNNER_TEMP}/codex-cli-bin-${TARGET}"
|
||||
out_dir="${GITHUB_WORKSPACE}/dist-python/${TARGET}"
|
||||
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install build hatchling
|
||||
|
||||
python sdk/python/scripts/update_sdk_artifacts.py \
|
||||
stage-runtime \
|
||||
"${staging_dir}" \
|
||||
"codex-rs/target/${TARGET}/release/codex" \
|
||||
--runtime-version "${version}"
|
||||
|
||||
python -m build --wheel --outdir "${out_dir}" "${staging_dir}"
|
||||
|
||||
- name: Upload Python runtime wheel
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-runtime-${{ matrix.target }}
|
||||
path: dist-python/${{ matrix.target }}/*
|
||||
|
||||
- name: Stage artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -384,6 +419,7 @@ jobs:
|
||||
needs:
|
||||
- build
|
||||
- build-windows
|
||||
- build-python-sdk
|
||||
- shell-tool-mcp
|
||||
name: release
|
||||
runs-on: ubuntu-latest
|
||||
@@ -533,6 +569,190 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
build-python-sdk:
|
||||
name: build-python-sdk
|
||||
needs:
|
||||
- tag-check
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Build Python SDK artifacts
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version="${RELEASE_TAG#rust-v}"
|
||||
core_staging_dir="${RUNNER_TEMP}/codex-app-server-sdk-core"
|
||||
core_out_dir="${GITHUB_WORKSPACE}/dist-python/sdk-core"
|
||||
bundled_staging_dir="${RUNNER_TEMP}/codex-app-server-sdk"
|
||||
bundled_out_dir="${GITHUB_WORKSPACE}/dist-python/sdk"
|
||||
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install \
|
||||
build \
|
||||
hatchling \
|
||||
"datamodel-code-generator==0.31.2" \
|
||||
"ruff==0.11.13"
|
||||
|
||||
python sdk/python/scripts/update_sdk_artifacts.py generate-types
|
||||
|
||||
python sdk/python/scripts/update_sdk_artifacts.py \
|
||||
stage-sdk-core \
|
||||
"${core_staging_dir}" \
|
||||
--sdk-version "${version}"
|
||||
|
||||
python -m build --outdir "${core_out_dir}" "${core_staging_dir}"
|
||||
|
||||
python sdk/python/scripts/update_sdk_artifacts.py \
|
||||
stage-sdk \
|
||||
"${bundled_staging_dir}" \
|
||||
--sdk-version "${version}" \
|
||||
--runtime-version "${version}"
|
||||
|
||||
python -m build --outdir "${bundled_out_dir}" "${bundled_staging_dir}"
|
||||
|
||||
- name: Upload Python core SDK artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-sdk-core
|
||||
path: dist-python/sdk-core/*
|
||||
|
||||
- name: Upload Python SDK artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-sdk
|
||||
path: dist-python/sdk/*
|
||||
|
||||
publish-pypi-runtime:
|
||||
name: publish-pypi-runtime
|
||||
needs:
|
||||
- build
|
||||
- build-windows
|
||||
- release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
environment:
|
||||
name: pypi
|
||||
|
||||
steps:
|
||||
# Do not publish musl runtime wheels to PyPI yet. GNU and musl builds for
|
||||
# the same architecture currently infer the same wheel tag, which can make
|
||||
# the published Linux runtime nondeterministic.
|
||||
- name: Download macOS arm64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-aarch64-apple-darwin
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: Download macOS x64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-x86_64-apple-darwin
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: Download Linux GNU arm64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-aarch64-unknown-linux-gnu
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: Download Linux GNU x64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-x86_64-unknown-linux-gnu
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: Download Windows arm64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-aarch64-pc-windows-msvc
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: Download Windows x64 runtime wheel
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-runtime-x86_64-pc-windows-msvc
|
||||
path: dist-pypi/runtime
|
||||
|
||||
- name: List runtime wheels
|
||||
shell: bash
|
||||
run: ls -R dist-pypi/runtime
|
||||
|
||||
- name: Publish Python runtime wheels to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: dist-pypi/runtime/
|
||||
|
||||
publish-pypi-sdk-core:
|
||||
name: publish-pypi-sdk-core
|
||||
needs:
|
||||
- build-python-sdk
|
||||
- publish-pypi-runtime
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
environment:
|
||||
name: pypi
|
||||
|
||||
steps:
|
||||
- name: Download Python core SDK artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-sdk-core
|
||||
path: dist-pypi/sdk-core
|
||||
|
||||
- name: List core SDK artifacts
|
||||
shell: bash
|
||||
run: ls -R dist-pypi/sdk-core
|
||||
|
||||
- name: Publish Python core SDK to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: dist-pypi/sdk-core/
|
||||
|
||||
publish-pypi-sdk:
|
||||
name: publish-pypi-sdk
|
||||
needs:
|
||||
- build-python-sdk
|
||||
- publish-pypi-sdk-core
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
environment:
|
||||
name: pypi
|
||||
|
||||
steps:
|
||||
- name: Download bundled Python SDK artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: python-sdk
|
||||
path: dist-pypi/sdk
|
||||
|
||||
- name: List bundled SDK artifacts
|
||||
shell: bash
|
||||
run: ls -R dist-pypi/sdk
|
||||
|
||||
- name: Publish bundled Python SDK to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: dist-pypi/sdk/
|
||||
|
||||
# Publish to npm using OIDC authentication.
|
||||
# July 31, 2025: https://github.blog/changelog/2025-07-31-npm-trusted-publishing-with-oidc-is-generally-available/
|
||||
# npm docs: https://docs.npmjs.com/trusted-publishers
|
||||
|
||||
@@ -11,9 +11,16 @@ cd sdk/python
|
||||
python -m pip install -e .
|
||||
```
|
||||
|
||||
Published SDK builds pin an exact `codex-cli-bin` runtime dependency. For local
|
||||
repo development, pass `AppServerConfig(codex_bin=...)` to point at a local
|
||||
build explicitly.
|
||||
This checked-in package is the runtime-free core distribution:
|
||||
`codex-app-server-sdk-core`.
|
||||
|
||||
Published releases expose two Python package names:
|
||||
|
||||
- `codex-app-server-sdk-core`: the actual Python SDK code, without bundled binaries
|
||||
- `codex-app-server-sdk`: a bundled metapackage that depends on `codex-app-server-sdk-core` and `codex-cli-bin`
|
||||
|
||||
For local repo development, pass `AppServerConfig(codex_bin=...)` to point at
|
||||
a local build explicitly.
|
||||
|
||||
## Quickstart
|
||||
|
||||
@@ -48,9 +55,9 @@ python examples/01_quickstart_constructor/async.py
|
||||
|
||||
The repo no longer checks `codex` binaries into `sdk/python`.
|
||||
|
||||
Published SDK builds are pinned to an exact `codex-cli-bin` package version,
|
||||
and that runtime package carries the platform-specific binary for the target
|
||||
wheel.
|
||||
Published `codex-app-server-sdk` builds depend on an exact
|
||||
`codex-app-server-sdk-core` version plus an exact `codex-cli-bin` version, and
|
||||
that runtime package carries the platform-specific binary for the target wheel.
|
||||
|
||||
For local repo development, the checked-in `sdk/python-runtime` package is only
|
||||
a template for staged release artifacts. Editable installs should use an
|
||||
@@ -61,9 +68,14 @@ explicit `codex_bin` override instead.
|
||||
```bash
|
||||
cd sdk/python
|
||||
python scripts/update_sdk_artifacts.py generate-types
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-sdk-core \
|
||||
/tmp/codex-python-release/codex-app-server-sdk-core \
|
||||
--sdk-version 1.2.3
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-sdk \
|
||||
/tmp/codex-python-release/codex-app-server-sdk \
|
||||
--sdk-version 1.2.3 \
|
||||
--runtime-version 1.2.3
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-runtime \
|
||||
@@ -75,17 +87,22 @@ python scripts/update_sdk_artifacts.py \
|
||||
This supports the CI release flow:
|
||||
|
||||
- run `generate-types` before packaging
|
||||
- stage `codex-app-server-sdk` once with an exact `codex-cli-bin==...` dependency
|
||||
- stage `codex-app-server-sdk-core` with the release tag version as `--sdk-version`
|
||||
- stage `codex-app-server-sdk` as a bundled metapackage pinned to exact `codex-app-server-sdk-core==...` and `codex-cli-bin==...`
|
||||
- stage `codex-cli-bin` on each supported platform runner with the same pinned runtime version
|
||||
- build and publish `codex-cli-bin` as platform wheels only; do not publish an sdist
|
||||
- publish `codex-app-server-sdk-core` to PyPI after the runtime wheels land
|
||||
- publish `codex-app-server-sdk` to PyPI last, using the same release version
|
||||
|
||||
## Compatibility and versioning
|
||||
|
||||
- Package: `codex-app-server-sdk`
|
||||
- Core package: `codex-app-server-sdk-core`
|
||||
- Bundled package: `codex-app-server-sdk`
|
||||
- Runtime package: `codex-cli-bin`
|
||||
- Current SDK version in this repo: `0.2.0`
|
||||
- Python: `>=3.10`
|
||||
- Target protocol: Codex `app-server` JSON-RPC v2
|
||||
- Release policy: published Python package versions should match the `rust-v...` release tag
|
||||
- Recommendation: keep SDK and `codex` CLI reasonably up to date together
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -38,16 +38,23 @@ Common causes:
|
||||
- local auth/session is missing
|
||||
- incompatible/old app-server
|
||||
|
||||
Maintainers stage releases by building the SDK once and the runtime once per
|
||||
platform with the same pinned runtime version. Publish `codex-cli-bin` as
|
||||
platform wheels only; do not publish an sdist:
|
||||
Maintainers stage releases by building the core SDK once, the bundled SDK
|
||||
metapackage once, and the runtime once per platform with the same pinned
|
||||
runtime version. Publish `codex-cli-bin` as platform wheels only; do not
|
||||
publish an sdist. Published Python package versions should match the
|
||||
`rust-v...` release tag:
|
||||
|
||||
```bash
|
||||
cd sdk/python
|
||||
python scripts/update_sdk_artifacts.py generate-types
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-sdk-core \
|
||||
/tmp/codex-python-release/codex-app-server-sdk-core \
|
||||
--sdk-version 1.2.3
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-sdk \
|
||||
/tmp/codex-python-release/codex-app-server-sdk \
|
||||
--sdk-version 1.2.3 \
|
||||
--runtime-version 1.2.3
|
||||
python scripts/update_sdk_artifacts.py \
|
||||
stage-runtime \
|
||||
|
||||
@@ -3,9 +3,9 @@ requires = ["hatchling>=1.24.0"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "codex-app-server-sdk"
|
||||
name = "codex-app-server-sdk-core"
|
||||
version = "0.2.0"
|
||||
description = "Python SDK for Codex app-server v2"
|
||||
description = "Core Python SDK for Codex app-server v2"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = { text = "Apache-2.0" }
|
||||
|
||||
@@ -15,8 +15,13 @@ import types
|
||||
import typing
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from typing import Any, Callable, Sequence, get_args, get_origin
|
||||
|
||||
CORE_SDK_PKG_NAME = "codex-app-server-sdk-core"
|
||||
BUNDLED_SDK_PKG_NAME = "codex-app-server-sdk"
|
||||
RUNTIME_PKG_NAME = "codex-cli-bin"
|
||||
|
||||
|
||||
def repo_root() -> Path:
|
||||
return Path(__file__).resolve().parents[3]
|
||||
@@ -110,23 +115,7 @@ def _rewrite_project_version(pyproject_text: str, version: str) -> str:
|
||||
return updated
|
||||
|
||||
|
||||
def _rewrite_sdk_runtime_dependency(pyproject_text: str, runtime_version: str) -> str:
|
||||
match = re.search(r"^dependencies = \[(.*?)\]$", pyproject_text, flags=re.MULTILINE)
|
||||
if match is None:
|
||||
raise RuntimeError(
|
||||
"Could not find dependencies array in sdk/python/pyproject.toml"
|
||||
)
|
||||
|
||||
raw_items = [item.strip() for item in match.group(1).split(",") if item.strip()]
|
||||
raw_items = [item for item in raw_items if "codex-cli-bin" not in item]
|
||||
raw_items.append(f'"codex-cli-bin=={runtime_version}"')
|
||||
replacement = "dependencies = [\n " + ",\n ".join(raw_items) + ",\n]"
|
||||
return pyproject_text[: match.start()] + replacement + pyproject_text[match.end() :]
|
||||
|
||||
|
||||
def stage_python_sdk_package(
|
||||
staging_dir: Path, sdk_version: str, runtime_version: str
|
||||
) -> Path:
|
||||
def stage_python_core_sdk_package(staging_dir: Path, sdk_version: str) -> Path:
|
||||
_copy_package_tree(sdk_root(), staging_dir)
|
||||
sdk_bin_dir = staging_dir / "src" / "codex_app_server" / "bin"
|
||||
if sdk_bin_dir.exists():
|
||||
@@ -135,11 +124,73 @@ def stage_python_sdk_package(
|
||||
pyproject_path = staging_dir / "pyproject.toml"
|
||||
pyproject_text = pyproject_path.read_text()
|
||||
pyproject_text = _rewrite_project_version(pyproject_text, sdk_version)
|
||||
pyproject_text = _rewrite_sdk_runtime_dependency(pyproject_text, runtime_version)
|
||||
pyproject_path.write_text(pyproject_text)
|
||||
return staging_dir
|
||||
|
||||
|
||||
def stage_python_sdk_package(
|
||||
staging_dir: Path, sdk_version: str, runtime_version: str
|
||||
) -> Path:
|
||||
if staging_dir.exists():
|
||||
if staging_dir.is_dir():
|
||||
shutil.rmtree(staging_dir)
|
||||
else:
|
||||
staging_dir.unlink()
|
||||
|
||||
package_dir = staging_dir / "src" / "codex_app_server_sdk_meta"
|
||||
package_dir.mkdir(parents=True, exist_ok=True)
|
||||
(package_dir / "__init__.py").write_text(
|
||||
'"""Bundled Codex app-server SDK package metadata."""\n'
|
||||
)
|
||||
|
||||
pyproject = dedent(
|
||||
f"""
|
||||
[build-system]
|
||||
requires = ["hatchling>=1.24.0"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "{BUNDLED_SDK_PKG_NAME}"
|
||||
version = "{sdk_version}"
|
||||
description = "Bundled Python SDK for Codex app-server v2"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = {{ text = "Apache-2.0" }}
|
||||
authors = [{{ name = "OpenClaw Assistant" }}]
|
||||
dependencies = [
|
||||
"{CORE_SDK_PKG_NAME}=={sdk_version}",
|
||||
"{RUNTIME_PKG_NAME}=={runtime_version}",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/openai/codex"
|
||||
Repository = "https://github.com/openai/codex"
|
||||
Issues = "https://github.com/openai/codex/issues"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/codex_app_server_sdk_meta"]
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
include = ["src/codex_app_server_sdk_meta/**", "README.md", "pyproject.toml"]
|
||||
"""
|
||||
).lstrip()
|
||||
(staging_dir / "pyproject.toml").write_text(pyproject)
|
||||
(staging_dir / "README.md").write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"# Codex App Server Python SDK",
|
||||
"",
|
||||
"Bundled metapackage for the Codex app-server Python SDK.",
|
||||
f"It depends on `{CORE_SDK_PKG_NAME}` and `{RUNTIME_PKG_NAME}`",
|
||||
"at the same version so a regular install includes both the SDK",
|
||||
"and the packaged Codex runtime binary.",
|
||||
"",
|
||||
]
|
||||
)
|
||||
)
|
||||
return staging_dir
|
||||
|
||||
|
||||
def stage_python_runtime_package(
|
||||
staging_dir: Path, runtime_version: str, binary_path: Path
|
||||
) -> Path:
|
||||
@@ -558,6 +609,7 @@ class PublicFieldSpec:
|
||||
@dataclass(frozen=True)
|
||||
class CliOps:
|
||||
generate_types: Callable[[], None]
|
||||
stage_python_core_sdk_package: Callable[[Path, str], Path]
|
||||
stage_python_sdk_package: Callable[[Path, str, str], Path]
|
||||
stage_python_runtime_package: Callable[[Path, str, Path], Path]
|
||||
current_sdk_version: Callable[[], str]
|
||||
@@ -916,23 +968,37 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
"generate-types", help="Regenerate Python protocol-derived types"
|
||||
)
|
||||
|
||||
stage_sdk_core_parser = subparsers.add_parser(
|
||||
"stage-sdk-core",
|
||||
help="Stage a releasable core SDK package without a bundled runtime",
|
||||
)
|
||||
stage_sdk_core_parser.add_argument(
|
||||
"staging_dir",
|
||||
type=Path,
|
||||
help="Output directory for the staged core SDK package",
|
||||
)
|
||||
stage_sdk_core_parser.add_argument(
|
||||
"--sdk-version",
|
||||
help="Version to write into the staged core SDK package (defaults to sdk/python current version)",
|
||||
)
|
||||
|
||||
stage_sdk_parser = subparsers.add_parser(
|
||||
"stage-sdk",
|
||||
help="Stage a releasable SDK package pinned to a runtime version",
|
||||
help="Stage a releasable bundled SDK metapackage pinned to a runtime version",
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"staging_dir",
|
||||
type=Path,
|
||||
help="Output directory for the staged SDK package",
|
||||
help="Output directory for the staged bundled SDK package",
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"--runtime-version",
|
||||
required=True,
|
||||
help="Pinned codex-cli-bin version for the staged SDK package",
|
||||
help="Pinned codex-cli-bin version for the staged bundled SDK package",
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"--sdk-version",
|
||||
help="Version to write into the staged SDK package (defaults to sdk/python current version)",
|
||||
help="Version to write into the staged bundled SDK package (defaults to sdk/python current version)",
|
||||
)
|
||||
|
||||
stage_runtime_parser = subparsers.add_parser(
|
||||
@@ -964,6 +1030,7 @@ def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
|
||||
def default_cli_ops() -> CliOps:
|
||||
return CliOps(
|
||||
generate_types=generate_types,
|
||||
stage_python_core_sdk_package=stage_python_core_sdk_package,
|
||||
stage_python_sdk_package=stage_python_sdk_package,
|
||||
stage_python_runtime_package=stage_python_runtime_package,
|
||||
current_sdk_version=current_sdk_version,
|
||||
@@ -973,6 +1040,12 @@ def default_cli_ops() -> CliOps:
|
||||
def run_command(args: argparse.Namespace, ops: CliOps) -> None:
|
||||
if args.command == "generate-types":
|
||||
ops.generate_types()
|
||||
elif args.command == "stage-sdk-core":
|
||||
ops.generate_types()
|
||||
ops.stage_python_core_sdk_package(
|
||||
args.staging_dir,
|
||||
args.sdk_version or ops.current_sdk_version(),
|
||||
)
|
||||
elif args.command == "stage-sdk":
|
||||
ops.generate_types()
|
||||
ops.stage_python_sdk_package(
|
||||
|
||||
@@ -47,6 +47,7 @@ from .retry import retry_on_overload
|
||||
|
||||
ModelT = TypeVar("ModelT", bound=BaseModel)
|
||||
ApprovalHandler = Callable[[str, JsonObject | None], JsonObject]
|
||||
BUNDLED_SDK_PKG_NAME = "codex-app-server-sdk"
|
||||
RUNTIME_PKG_NAME = "codex-cli-bin"
|
||||
|
||||
|
||||
@@ -82,9 +83,9 @@ def _installed_codex_path() -> Path:
|
||||
from codex_cli_bin import bundled_codex_path
|
||||
except ImportError as exc:
|
||||
raise FileNotFoundError(
|
||||
"Unable to locate the pinned Codex runtime. Install the published SDK build "
|
||||
f"with its {RUNTIME_PKG_NAME} dependency, or set AppServerConfig.codex_bin "
|
||||
"explicitly."
|
||||
"Unable to locate the Codex runtime. Install the published "
|
||||
f"{BUNDLED_SDK_PKG_NAME} package, install {RUNTIME_PKG_NAME} "
|
||||
"alongside the core SDK, or set AppServerConfig.codex_bin explicitly."
|
||||
) from exc
|
||||
|
||||
return bundled_codex_path()
|
||||
|
||||
@@ -117,7 +117,7 @@ def test_python_codegen_schema_annotation_adds_stable_variant_titles() -> None:
|
||||
]
|
||||
assert ask_for_approval_titles == [
|
||||
"AskForApprovalValue",
|
||||
"RejectAskForApproval",
|
||||
"GranularAskForApproval",
|
||||
]
|
||||
|
||||
reasoning_summary_titles = [
|
||||
@@ -238,17 +238,31 @@ def test_stage_runtime_release_replaces_existing_staging_dir(tmp_path: Path) ->
|
||||
assert script.staged_runtime_bin_path(staged).read_text() == "fake codex\n"
|
||||
|
||||
|
||||
def test_stage_sdk_release_injects_exact_runtime_pin(tmp_path: Path) -> None:
|
||||
def test_stage_core_sdk_release_sets_version_without_runtime_pin(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
staged = script.stage_python_core_sdk_package(tmp_path / "sdk-core-stage", "0.2.1")
|
||||
|
||||
pyproject = (staged / "pyproject.toml").read_text()
|
||||
assert 'version = "0.2.1"' in pyproject
|
||||
assert 'name = "codex-app-server-sdk-core"' in pyproject
|
||||
assert "codex-cli-bin" not in pyproject
|
||||
assert not any((staged / "src" / "codex_app_server").glob("bin/**"))
|
||||
|
||||
|
||||
def test_stage_bundled_sdk_release_injects_exact_core_and_runtime_pins(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
script = _load_update_script_module()
|
||||
staged = script.stage_python_sdk_package(tmp_path / "sdk-stage", "0.2.1", "1.2.3")
|
||||
|
||||
pyproject = (staged / "pyproject.toml").read_text()
|
||||
assert 'name = "codex-app-server-sdk"' in pyproject
|
||||
assert 'version = "0.2.1"' in pyproject
|
||||
assert '"codex-app-server-sdk-core==0.2.1"' in pyproject
|
||||
assert '"codex-cli-bin==1.2.3"' in pyproject
|
||||
assert not any((staged / "src" / "codex_app_server").glob("bin/**"))
|
||||
|
||||
|
||||
def test_stage_sdk_release_replaces_existing_staging_dir(tmp_path: Path) -> None:
|
||||
def test_stage_bundled_sdk_release_replaces_existing_staging_dir(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
staging_dir = tmp_path / "sdk-stage"
|
||||
old_file = staging_dir / "stale.txt"
|
||||
@@ -261,6 +275,49 @@ def test_stage_sdk_release_replaces_existing_staging_dir(tmp_path: Path) -> None
|
||||
assert not old_file.exists()
|
||||
|
||||
|
||||
def test_stage_sdk_core_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
calls: list[str] = []
|
||||
args = script.parse_args(
|
||||
[
|
||||
"stage-sdk-core",
|
||||
str(tmp_path / "sdk-core-stage"),
|
||||
]
|
||||
)
|
||||
|
||||
def fake_generate_types() -> None:
|
||||
calls.append("generate_types")
|
||||
|
||||
def fake_stage_core_sdk_package(_staging_dir: Path, _sdk_version: str) -> Path:
|
||||
calls.append("stage_sdk_core")
|
||||
return tmp_path / "sdk-core-stage"
|
||||
|
||||
def fake_stage_sdk_package(
|
||||
_staging_dir: Path, _sdk_version: str, _runtime_version: str
|
||||
) -> Path:
|
||||
raise AssertionError("bundled sdk staging should not run for stage-sdk-core")
|
||||
|
||||
def fake_stage_runtime_package(
|
||||
_staging_dir: Path, _runtime_version: str, _runtime_binary: Path
|
||||
) -> Path:
|
||||
raise AssertionError("runtime staging should not run for stage-sdk-core")
|
||||
|
||||
def fake_current_sdk_version() -> str:
|
||||
return "0.2.0"
|
||||
|
||||
ops = script.CliOps(
|
||||
generate_types=fake_generate_types,
|
||||
stage_python_core_sdk_package=fake_stage_core_sdk_package,
|
||||
stage_python_sdk_package=fake_stage_sdk_package,
|
||||
stage_python_runtime_package=fake_stage_runtime_package,
|
||||
current_sdk_version=fake_current_sdk_version,
|
||||
)
|
||||
|
||||
script.run_command(args, ops)
|
||||
|
||||
assert calls == ["generate_types", "stage_sdk_core"]
|
||||
|
||||
|
||||
def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
calls: list[str] = []
|
||||
@@ -276,6 +333,9 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
def fake_generate_types() -> None:
|
||||
calls.append("generate_types")
|
||||
|
||||
def fake_stage_core_sdk_package(_staging_dir: Path, _sdk_version: str) -> Path:
|
||||
raise AssertionError("core sdk staging should not run for stage-sdk")
|
||||
|
||||
def fake_stage_sdk_package(
|
||||
_staging_dir: Path, _sdk_version: str, _runtime_version: str
|
||||
) -> Path:
|
||||
@@ -292,6 +352,7 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
|
||||
ops = script.CliOps(
|
||||
generate_types=fake_generate_types,
|
||||
stage_python_core_sdk_package=fake_stage_core_sdk_package,
|
||||
stage_python_sdk_package=fake_stage_sdk_package,
|
||||
stage_python_runtime_package=fake_stage_runtime_package,
|
||||
current_sdk_version=fake_current_sdk_version,
|
||||
@@ -320,6 +381,9 @@ def test_stage_runtime_stages_binary_without_type_generation(tmp_path: Path) ->
|
||||
def fake_generate_types() -> None:
|
||||
calls.append("generate_types")
|
||||
|
||||
def fake_stage_core_sdk_package(_staging_dir: Path, _sdk_version: str) -> Path:
|
||||
raise AssertionError("core sdk staging should not run for stage-runtime")
|
||||
|
||||
def fake_stage_sdk_package(
|
||||
_staging_dir: Path, _sdk_version: str, _runtime_version: str
|
||||
) -> Path:
|
||||
@@ -336,6 +400,7 @@ def test_stage_runtime_stages_binary_without_type_generation(tmp_path: Path) ->
|
||||
|
||||
ops = script.CliOps(
|
||||
generate_types=fake_generate_types,
|
||||
stage_python_core_sdk_package=fake_stage_core_sdk_package,
|
||||
stage_python_sdk_package=fake_stage_sdk_package,
|
||||
stage_python_runtime_package=fake_stage_runtime_package,
|
||||
current_sdk_version=fake_current_sdk_version,
|
||||
|
||||
Reference in New Issue
Block a user