18 Commits

  • Allow ChatGPT accounts without email (#28991)
    # Summary
    
    Codex required every ChatGPT account to have an email address. A
    service-account personal access token can return valid account metadata
    without one, so PAT login failed while decoding the metadata response.
    
    This change makes email optional in the account metadata type that owns
    it and preserves that absence through authentication, provider account
    state, the app-server API, generated clients, and TUI bootstrap.
    Existing accounts with email addresses keep the same behavior.
    
    ## Behavior-changing call sites
    
    | Call site | Behavior after this change |
    | --- | --- |
    | `login/src/auth/personal_access_token.rs` | PAT metadata accepts a
    missing or null email and retains `None`. |
    | `agent-identity/src/lib.rs` | Agent Identity JWT claims accept an
    omitted email. |
    | `login/src/auth/storage.rs` and `login/src/auth/agent_identity.rs` |
    Stored and managed Agent Identity records carry `Option<String>`.
    Deserialization maps the legacy empty-string sentinel to `None`. |
    | `login/src/auth/manager.rs` | `get_account_email` returns the stored
    option, and managed identity bootstrap no longer converts `None` to an
    empty string. |
    | `model-provider/src/provider.rs` and `protocol/src/account.rs` | A
    ChatGPT provider account requires a plan type but may carry no email. |
    | `app-server-protocol/src/protocol/v2/account.rs` | `account/read`
    keeps the `email` field on the wire and returns `null` when the account
    has no email. Generated TypeScript and JSON schemas describe a required,
    nullable field. |
    | `sdk/python/src/openai_codex/generated/v2_all.py` | The generated
    Python `ChatgptAccount` model accepts `None` for email. |
    | `tui/src/app_server_session.rs` | Email-less ChatGPT accounts
    bootstrap normally, keep external feedback routing, omit account-email
    telemetry, and display the plan in account status. |
    
    ## Design decisions
    
    - Missing email remains `None` at every layer. The code never uses an
    empty string as a substitute.
    - The app-server response includes `"email": null` instead of omitting
    the field. Clients retain a stable response shape.
    - Plan type remains required for provider account state. This change
    relaxes only the email assumption.
    
    ## Testing
    
    Tests: affected test targets compile, scoped Clippy and formatting pass,
    a focused TUI snapshot covers plan-only account status, real
    before/after PAT login smoke covers metadata without email, app-server
    smoke covers `account/read` with `email: null`, and a regression smoke
    covers an existing email-bearing PAT. Unit tests run in CI.
    
    ## Evidence
    
    Visual smoke evidence will be attached here.
  • [codex] Pin Python SDK to glibc-compatible runtime (#25907)
    ## Summary
    - pin the Python SDK runtime package to `openai-codex-cli-bin==0.136.0`
    so Ubuntu/glibc installs resolve a compatible wheel
    - refresh generated SDK artifacts and lock data for the runtime update
    - keep newly generated client-message-id wire models internal to the
    generated protocol layer
    
    ## Dependency
    - merge #25906 first so the Python SDK release publishes both manylinux
    and musllinux runtime wheels before publishing the package with this pin
    
    ## Validation
    - ran `just fmt`
    - regenerated the Python public API helpers
    - validated the edited workflow YAML
    - CI passed 29/29 checks
  • [codex] Prepare Python SDK beta documentation and package metadata (#24836)
    ## Why
    
    The initial public `openai-codex` beta should read and install like a
    normal published Python package before a release tag is created. This
    follows merged PR #24828, which establishes the independent SDK beta
    release plumbing and exact runtime dependency.
    
    ## What changed
    
    - Rewrote `sdk/python/README.md` as a compact PyPI-facing beta package
    page: published installation, one quickstart, short login examples,
    built-in help, and links to deeper guides.
    - Updated the getting-started guide, API reference, FAQ, and examples
    index to present the published beta consistently without repeating
    onboarding in the package landing page or reference page.
    - Made `pip install openai-codex` the primary install path while beta
    releases are the only published SDK releases, with `--pre` documented
    for opting into prereleases after a stable release exists.
    - Added curated `help()` / `pydoc` docstrings across the public API and
    generated public convenience methods through
    `scripts/update_sdk_artifacts.py`.
    - Declared the repository `Apache-2.0` license expression and
    Documentation URL in package metadata, without introducing a duplicated
    SDK-local license file.
    - Kept the source distribution focused on installable package material
    (`src/openai_codex`, `README.md`, and `pyproject.toml`); the repository
    docs and runnable examples remain linked from the PyPI README.
    - Built release artifacts in an Alpine container on the Ubuntu runner,
    matching Python SDK CI and allowing type generation to install the
    published `musllinux` runtime wheel.
    - Added `twine check --strict` to the release workflow so malformed PyPI
    metadata or rendered README content fails before publishing.
    - Added focused SDK assertions for beta metadata, the exact runtime pin,
    source distribution contents, and the built-in Python documentation
    surface.
    
    ## Validation
    
    - Ran `uv run --frozen --extra dev ruff check
    scripts/update_sdk_artifacts.py src/openai_codex
    tests/test_public_api_signatures.py
    tests/test_artifact_workflow_and_binaries.py` before the final
    README-only reductions and review-fix follow-ups.
    - Built `openai_codex-0.1.0b1-py3-none-any.whl` and
    `openai_codex-0.1.0b1.tar.gz` before the final README-only reductions
    and review-fix follow-ups.
    - Ran `python -m twine check --strict` on both built artifacts before
    the final README-only reductions and review-fix follow-ups.
    - Verified artifact metadata reports `Apache-2.0` without a duplicated
    SDK-local license file.
    - Verified `inspect.getdoc(...)` resolves documentation for the package,
    `Codex`, `CodexConfig`, and key generated thread methods.
    - Rebased the documentation/readiness change onto merged PR #24828
    without changing the intended SDK or workflow file contents.
    - Final verification is delegated to online CI for this PR.
  • [codex] Add independent beta release for the Python SDK (#24828)
    ## Why
    
    `openai-codex` needs a beta release lifecycle without requiring beta
    releases of its pinned runtime package. Previously, SDK staging rewrote
    its runtime dependency to the SDK version, which made an SDK-only beta
    impossible.
    
    ## What changed
    
    - Set the initial SDK beta version to `0.1.0b1` and pin it to published
    stable `openai-codex-cli-bin==0.132.0`.
    - Decoupled SDK release staging from runtime versioning so it preserves
    the reviewed exact runtime pin.
    - Added a `python-v*` tag workflow that builds and publishes only
    `openai-codex` through PyPI trusted publishing.
    - Removed the Beta classifier from runtime package metadata for future
    runtime publications.
    - Regenerated protocol-derived SDK models from the selected stable
    runtime package.
    
    `0.132.0` is the newest stable runtime admitted by the checked-in
    dependency date fence and retains the Linux wheel family currently used
    by SDK CI.
    
    ## Release setup
    
    Before pushing `python-v0.1.0b1`, configure PyPI trusted publishing for
    the `openai-codex` project with workflow `python-sdk-release.yml`,
    environment `pypi`, and job `publish-python-sdk`.
    
    ## Validation
    
    - `uv run --frozen --extra dev ruff check src/openai_codex scripts
    examples tests`
    - Parsed `.github/workflows/python-sdk-release.yml` with PyYAML.
    - Built staged release artifacts locally:
    `openai_codex-0.1.0b1-py3-none-any.whl` and
    `openai_codex-0.1.0b1.tar.gz`.
    - Verified wheel metadata pins `openai-codex-cli-bin==0.132.0`.
    - Tests are deferred to online CI for this PR.
  • [codex] Add friendly Python SDK sandbox presets (#24772)
    ## Why
    
    The Python SDK currently exposes sandbox selection differently depending
    on where it is used: thread lifecycle methods accept `SandboxMode`,
    while turns accept the lower-level `SandboxPolicy` shape. For the common
    case of choosing an access level, that leaks app-server wire details
    into otherwise straightforward SDK usage.
    
    This makes the common path explicit and discoverable: callers choose a
    named sandbox preset once, using the same keyword on threads and turns.
    The preset name `workspace_write` also makes the granted capability
    clear at the callsite.
    
    ## What changed
    
    - Added a root-level `Sandbox` enum with documented presets:
      - `Sandbox.read_only`: read files without allowing writes.
    - `Sandbox.workspace_write`: the normal default for projects with a
    recorded trust decision; read files and write inside the workspace and
    configured writable roots.
      - `Sandbox.full_access`: run without filesystem access restrictions.
    - Documented that omitting `sandbox=` delegates to app-server's
    configured default, while explicit turn overrides remain sticky for
    subsequent turns.
    - Updated sync and async thread lifecycle and turn APIs to consistently
    accept `sandbox=Sandbox...`, translating to the existing app-server
    thread and turn representations internally.
    - Updated the public API artifact generator so regenerated SDK wrappers
    retain the friendly enum shape.
    - Replaced low-level policy construction in Python docs, examples, and
    the walkthrough notebook with the preset API.
    - Added focused coverage for root exports, method signatures,
    preset-to-wire mapping, and rejection of raw string sandbox inputs.
    
    ## API impact
    
    High-level turn calls now use `sandbox=` instead of `sandbox_policy=`:
    
    ```python
    from openai_codex import Codex, Sandbox
    
    with Codex() as codex:
        thread = codex.thread_start(sandbox=Sandbox.workspace_write)
        result = thread.run("Review the diff only.", sandbox=Sandbox.read_only)
    ```
    
    `thread_start(...)` already defaults to `ApprovalMode.auto_review`, so
    normal writable usage is concise:
    
    ```python
    with Codex() as codex:
        thread = codex.thread_start(sandbox=Sandbox.workspace_write)
        thread.run("Update the files in this workspace.")
    ```
    
    With that combination, edits inside `cwd` and configured writable roots
    run within the workspace-write sandbox. Operations that require
    approval, such as edits outside those roots, are routed through auto
    review. When `sandbox=` is omitted, app-server resolves its configured
    default. A sandbox supplied to `run(...)` or `turn(...)` applies to that
    turn and subsequent turns.
    
    ## Test coverage
    
    - `sdk/python/tests/test_public_api_signatures.py` covers the public
    export and parameter names, including the default approval mode.
    - `sdk/python/tests/test_public_api_runtime_behavior.py` covers preset
    mappings to the existing wire types and raw string rejection.
  • sdk: launch packaged Codex runtimes (#23786)
    ## Why
    
    The Python and TypeScript SDKs launch the native Codex runtime directly,
    so they need to consume the same package artifact shape that release
    jobs now produce. The runtime wheel should be built from the canonical
    Codex package archive rather than reconstructing a parallel layout from
    loose binaries.
    
    ## What Changed
    
    - Stage `openai-codex-cli-bin` by extracting
    `codex-package-<target>.tar.gz` into `src/codex_cli_bin` and validating
    the expected package layout.
    - Update release workflows to pass the generated package archive into
    `stage-runtime` instead of the temporary package directory.
    - Update Python runtime setup to download `codex-package-*.tar.gz`
    release assets directly.
    - Expose Python runtime helpers for the bundled package directory and
    `codex-path`, and prepend that path when `openai_codex` launches the
    installed runtime without duplicating Windows `Path`/`PATH` keys.
    - Teach the TypeScript SDK to resolve package-layout optional
    dependencies while keeping the existing npm fallback layout, and
    preserve the existing Windows path variable casing when prepending
    `codex-path`.
    
    ## Test Plan
    
    - `python3 -m py_compile sdk/python/scripts/update_sdk_artifacts.py
    sdk/python/_runtime_setup.py sdk/python/src/openai_codex/client.py
    sdk/python-runtime/src/codex_cli_bin/__init__.py`
    - `uv run --frozen --project sdk/python --extra dev ruff check
    sdk/python/scripts/update_sdk_artifacts.py sdk/python/_runtime_setup.py
    sdk/python/src/openai_codex/client.py
    sdk/python/tests/test_artifact_workflow_and_binaries.py
    sdk/python-runtime/src/codex_cli_bin/__init__.py`
    - `uv run --frozen --project sdk/python --extra dev pytest
    sdk/python/tests/test_artifact_workflow_and_binaries.py`
    - `pnpm eslint src/exec.ts tests/exec.test.ts`
    - `pnpm test --runInBand tests/exec.test.ts`
  • [codex] Accept string input for Python turns (#23162)
    ## Summary
    - Allow thread.turn and turn.steer, including async variants, to accept
    RunInput so plain strings work alongside typed input objects.
    - Export RunInput and update the SDK artifact generator so regenerated
    turn methods keep the same signature and normalization.
    - Update docs, examples, notebook cells, and tests to use string
    shorthand for text-only turns while keeping typed inputs for multimodal
    input.
    
    ## Validation
    - uv run --extra dev ruff format .
    - uv run --extra dev ruff check --output-format=github .
    - python3 -m py_compile sdk/python/src/openai_codex/__init__.py
    sdk/python/src/openai_codex/api.py
    sdk/python/src/openai_codex/_inputs.py
    sdk/python/scripts/update_sdk_artifacts.py
    sdk/python/tests/test_public_api_signatures.py
    sdk/python/tests/test_app_server_streaming.py
    sdk/python/tests/test_app_server_turn_controls.py
    sdk/python/tests/test_real_app_server_integration.py
    - python3 -c "import json;
    json.load(open('sdk/python/notebooks/sdk_walkthrough.ipynb'))"
    - sdk/python/.venv/bin/python -c "import inspect, openai_codex; from
    openai_codex import Thread, AsyncThread, TurnHandle, AsyncTurnHandle,
    RunInput; funcs=[Thread.run, Thread.turn, AsyncThread.run,
    AsyncThread.turn, TurnHandle.steer, AsyncTurnHandle.steer]; assert
    all(inspect.signature(fn).parameters['input'].annotation == 'RunInput'
    for fn in funcs); assert RunInput is openai_codex.RunInput"
  • [8/8] Add Python SDK Ruff formatting (#22021)
    ## Why
    
    The Python SDK needs the same tight formatter/lint loop as the rest of
    the repo: a safe Ruff autofix pass, Ruff formatting, editor save
    behavior, and CI checks that catch drift. Without that loop, SDK changes
    can land with formatting or import ordering that differs from what
    reviewers and CI expect.
    
    ## What
    
    - Add Ruff configuration to `sdk/python/pyproject.toml`, excluding
    generated protocol code and notebooks from the normal lint/format pass.
    - Update `just fmt` so it still formats Rust and also runs Python SDK
    Ruff autofix and formatting.
    - Add Python SDK CI steps for `ruff check` and `ruff format --check`
    before pytest.
    - Recommend the Ruff VS Code extension and enable Python
    format/fix/organize-on-save so Cmd+S uses the same tooling.
    - Apply the resulting Ruff formatting to SDK Python files, examples, and
    the checked-in generated `v2_all.py` output emitted by the pinned
    generator.
    - Add a guard test for the `just fmt` recipe so it keeps working from
    both Rust and Python SDK working directories.
    
    ## Stack
    
    1. #21891 `[1/8]` Pin Python SDK runtime dependency
    2. #21893 `[2/8]` Generate Python SDK types from pinned runtime
    3. #21895 `[3/8]` Run Python SDK tests in CI
    4. #21896 `[4/8]` Define Python SDK public API surface
    5. #21905 `[5/8]` Rename Python SDK package to `openai-codex`
    6. #21910 `[6/8]` Add high-level Python SDK approval mode
    7. #22014 `[7/8]` Add Python SDK app-server integration harness
    8. This PR `[8/8]` Add Python SDK Ruff formatting
    
    ## Verification
    
    - Added `test_root_fmt_recipe_formats_rust_and_python_sdk` for the
    shared format recipe.
    - Ran `just fmt` after the recipe update.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [6/8] Add high-level Python SDK approval mode (#21910)
    ## Why
    
    The high-level SDK should expose the approval behavior it actually
    supports instead of leaking generated app-server routing fields. New
    work should have two clear choices: default auto review, or explicitly
    deny escalated permission requests. Existing threads and subsequent
    turns should preserve their current approval behavior unless the caller
    passes an override.
    
    ## What
    
    - Add the public `ApprovalMode` enum with `auto_review` and `deny_all`.
    - Default new thread creation to `ApprovalMode.auto_review`.
    - Preserve existing approval settings by default for resume, fork, run,
    and turn helpers.
    - Remove raw `approval_policy` / `approvals_reviewer` kwargs from
    high-level SDK wrappers.
    - Update generated wrapper output, docs, examples, notebooks, and tests
    for the high-level approval mode API.
    
    ## Stack
    
    1. #21891 `[1/8]` Pin Python SDK runtime dependency
    2. #21893 `[2/8]` Generate Python SDK types from pinned runtime
    3. #21895 `[3/8]` Run Python SDK tests in CI
    4. #21896 `[4/8]` Define Python SDK public API surface
    5. #21905 `[5/8]` Rename Python SDK package to `openai-codex`
    6. This PR `[6/8]` Add high-level Python SDK approval mode
    7. #22014 `[7/8]` Add Python SDK app-server integration harness
    8. #22021 `[8/8]` Add Python SDK Ruff formatting
    
    ## Verification
    
    - Added approval-mode mapping/default tests for new threads, existing
    threads, forks, resumes, and subsequent turns.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [5/8] Rename Python SDK package to openai-codex (#21905)
    ## Why
    
    The SDK should publish under the reserved public distribution name
    `openai-codex`, and its import module should match that name in the
    Python style. Since package names can contain hyphens but import modules
    cannot, the public import path becomes `openai_codex`.
    
    Keeping the rename separate from the public API surface change makes the
    naming change easy to review and avoids mixing it with API curation.
    
    ## What
    
    - Rename the SDK distribution from `openai-codex-app-server-sdk` to
    `openai-codex`.
    - Rename the import package from `codex_app_server` to `openai_codex`.
    - Keep the runtime wheel as the separate `openai-codex-cli-bin`
    dependency.
    - Update docs, examples, notebooks, artifact scripts, lockfile metadata,
    and tests for the new distribution/module names.
    
    ## Stack
    
    1. #21891 `[1/8]` Pin Python SDK runtime dependency
    2. #21893 `[2/8]` Generate Python SDK types from pinned runtime
    3. #21895 `[3/8]` Run Python SDK tests in CI
    4. #21896 `[4/8]` Define Python SDK public API surface
    5. This PR `[5/8]` Rename Python SDK package to `openai-codex`
    6. #21910 `[6/8]` Add high-level Python SDK approval mode
    7. #22014 `[7/8]` Add Python SDK app-server integration harness
    8. #22021 `[8/8]` Add Python SDK Ruff formatting
    
    ## Verification
    
    - Updated package metadata and public API tests to assert the
    distribution and import names.
    
    Co-authored-by: Codex <noreply@openai.com>
  • [2/8] Generate Python SDK types from pinned runtime (#21893)
    ## Why
    
    Once the SDK declares its runtime package, generated Python artifacts
    should come from that pinned runtime rather than whatever app-server
    schema happens to be in the current checkout. That keeps the generated
    API and model surface aligned with the runtime users install.
    
    ## What
    
    - Teach `scripts/update_sdk_artifacts.py generate-types` to invoke the
    pinned runtime package for schema generation.
    - Regenerate `v2_all.py`, `notification_registry.py`, and generated
    public wrapper methods from that schema.
    - Add freshness coverage so regenerating from the pinned runtime must
    leave checked-in artifacts unchanged.
    
    ## Stack
    
    1. #21891 `[1/8]` Pin Python SDK runtime dependency
    2. This PR `[2/8]` Generate Python SDK types from pinned runtime
    3. #21895 `[3/8]` Run Python SDK tests in CI
    4. #21896 `[4/8]` Define Python SDK public API surface
    5. #21905 `[5/8]` Rename Python SDK package to `openai-codex`
    6. #21910 `[6/8]` Add high-level Python SDK approval mode
    7. #22014 `[7/8]` Add Python SDK app-server integration harness
    8. #22021 `[8/8]` Add Python SDK Ruff formatting
    
    ## Verification
    
    - Added `test_generated_files_are_up_to_date` for pinned-runtime
    generation drift.
    - Added generator-structure tests for schema annotation and notification
    metadata generation.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [1/8] Pin Python SDK runtime dependency (#21891)
    ## Why
    
    The Python SDK depends on the app-server runtime package for the bundled
    `codex` binary and schema source of truth. That relationship should be
    explicit in package metadata instead of inferred from matching version
    numbers, so installers, lockfiles, and reviewers can see exactly which
    runtime the SDK expects.
    
    ## What
    
    - Declare `openai-codex-cli-bin==0.131.0a4` as a Python SDK dependency.
    - Update runtime setup helpers to resolve the runtime version from the
    declared dependency pin.
    - Refresh the SDK lockfile for the pinned runtime wheel.
    - Update package/runtime tests and docs that describe where the runtime
    version comes from.
    
    ## Stack
    
    1. This PR `[1/8]` Pin Python SDK runtime dependency
    2. #21893 `[2/8]` Generate Python SDK types from pinned runtime
    3. #21895 `[3/8]` Run Python SDK tests in CI
    4. #21896 `[4/8]` Define Python SDK public API surface
    5. #21905 `[5/8]` Rename Python SDK package to `openai-codex`
    6. #21910 `[6/8]` Add high-level Python SDK approval mode
    7. #22014 `[7/8]` Add Python SDK app-server integration harness
    8. #22021 `[8/8]` Add Python SDK Ruff formatting
    
    ## Verification
    
    - Added coverage for the SDK runtime dependency pin and runtime
    distribution naming.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Route Python SDK turn notifications by ID (#21778)
    ## Why
    
    The Python SDK previously protected the stdio transport with a single
    active turn-consumer guard. That avoided competing reads from stdout,
    but it also meant one `Codex`/`AsyncCodex` client could not stream
    multiple active turns at the same time. Notifications could also arrive
    before the caller received a `TurnHandle` and registered for streaming,
    so the SDK needed an explicit routing layer instead of letting
    individual API calls read directly from the shared transport.
    
    ## What Changed
    
    - Added a private `MessageRouter` that owns per-request response queues,
    per-turn notification queues, pending turn-notification replay, and
    global notification delivery behind a single stdout reader thread.
    - Generated typed notification routing metadata so turn IDs come from
    known payload shapes instead of router-side attribute guessing, with
    explicit fallback handling for unknown notification payloads.
    - Updated sync and async turn streaming so `TurnHandle.stream()`/`run()`
    and `stream_text()` consume only notifications for their own turn ID,
    while `AsyncAppServerClient` no longer serializes all transport calls
    behind one async lock.
    - Cleared pending turn-notification buffers when unregistered turns
    complete so never-consumed turn handles do not leave stale queues
    behind.
    - Removed the internal stream-until helper now that turn completion
    waiting can register directly with routed turn notifications.
    - Updated Python SDK docs and focused tests for concurrent transport
    calls, interleaved turn routing, buffered early notifications, unknown
    notification routing, async delegation, and routed turn completion
    behavior.
    
    ## Validation
    
    - `uv run --extra dev ruff format scripts/update_sdk_artifacts.py
    src/codex_app_server/_message_router.py src/codex_app_server/client.py
    src/codex_app_server/generated/notification_registry.py
    tests/test_client_rpc_methods.py
    tests/test_public_api_runtime_behavior.py
    tests/test_async_client_behavior.py`
    - `uv run --extra dev ruff check scripts/update_sdk_artifacts.py
    src/codex_app_server/_message_router.py src/codex_app_server/client.py
    src/codex_app_server/generated/notification_registry.py
    tests/test_client_rpc_methods.py
    tests/test_public_api_runtime_behavior.py
    tests/test_async_client_behavior.py`
    - `uv run --extra dev pytest tests/test_client_rpc_methods.py
    tests/test_public_api_runtime_behavior.py
    tests/test_async_client_behavior.py`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Support resource binaries in Python runtime staging (#21787)
    ## Why
    
    Some Codex runtime distributions need helper executables beside the main
    bundled binary. Linux sandbox fallback needs a packaged `bwrap` when no
    suitable system `bwrap` is available, and Windows sandbox/elevation
    needs helper executables discoverable beside `codex.exe`. The checked-in
    `openai-codex-cli-bin` template already packages everything under
    `codex_cli_bin/bin/**`, but the staging script only copied the main
    Codex binary into that directory.
    
    This PR adds the generic staging primitive needed by release workflows
    to build complete platform runtime wheels without baking
    platform-specific helper names into the package template.
    
    ## What changed
    
    - Added repeatable `stage-runtime --resource-binary` support so release
    workflows can copy extra executables beside the bundled Codex binary.
    - Kept resource selection in workflow code, where the platform target is
    known.
    - Added tests that verify resource binaries are copied into the staged
    runtime package, that the wheel include config covers them, and that the
    CLI forwards repeated `--resource-binary` values.
    
    ## Testing
    
    - `uv run ruff check scripts/update_sdk_artifacts.py
    tests/test_artifact_workflow_and_binaries.py`
    - `uv run --extra dev pytest
    tests/test_artifact_workflow_and_binaries.py::test_stage_runtime_release_copies_resource_binaries
    tests/test_artifact_workflow_and_binaries.py::test_runtime_resource_binaries_are_included_by_wheel_config
    tests/test_artifact_workflow_and_binaries.py::test_stage_runtime_stages_binary_without_type_generation`
    
    Full `tests/test_artifact_workflow_and_binaries.py` still has unrelated
    schema-normalization drift in the local checkout.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • 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()`.
  • Stage publishable Python runtime wheels (#18865)
    This is PR 2 of the Python SDK PyPI publishing split. [PR
    1](https://github.com/openai/codex/pull/18862) refreshed the generated
    SDK bindings; this PR makes the runtime package itself publishable, and
    PR 3 will wire the SDK package/version pinning to this runtime package.
    
    ## Summary
    - Rename the runtime distribution to `openai-codex-cli-bin` while
    keeping the import package as `codex_cli_bin`.
    - Make the runtime package wheel-only and build `py3-none-<platform>`
    wheels instead of interpreter-specific wheels.
    - Add `stage-runtime --codex-version` and `--platform-tag` so release
    staging can produce the platform wheel matrix from Codex release tags.
    - Add focused artifact workflow tests for version normalization,
    platform tag injection, and runtime wheel metadata.
    
    ## Why Rename
    There is already an unofficial PyPI package,
    [`codex-bin`](https://pypi.org/project/codex-bin/), distributing OpenAI
    Codex binaries. Publishing the official SDK runtime dependency as
    `openai-codex-cli-bin` makes the ownership clear, avoids confusing the
    SDK-pinned runtime wheel with that unowned wrapper, and keeps the import
    package unchanged as `codex_cli_bin`.
    
    ## Tests
    - `uv run --extra dev pytest
    tests/test_artifact_workflow_and_binaries.py` -> 21 passed
    - `uv run --extra dev python scripts/update_sdk_artifacts.py
    stage-runtime /tmp/codex-python-pr2-rebased/runtime-stage
    /tmp/codex-python-pr2-rebased/codex --codex-version
    rust-v0.116.0-alpha.1 --platform-tag macosx_11_0_arm64`
    - `uv run --with build --extra dev python -m build --wheel
    /tmp/codex-python-pr2-rebased/runtime-stage`
    - `uv run --with twine --extra dev twine check
    /tmp/codex-python-pr2-rebased/runtime-stage/dist/openai_codex_cli_bin-0.116.0a1-py3-none-macosx_11_0_arm64.whl`
    
    ## Note
    - Full `uv run --extra dev pytest` currently fails because regenerating
    from schemas already on `main` adds new DeviceKey Python types. I left
    that generated catch-up out of this runtime-only PR.
  • Add Python SDK public API and examples (#14446)
    ## TL;DR
    WIP esp the examples
    
    Thin the Python SDK public surface so the wrapper layer returns
    canonical app-server generated models directly.
    
    - keeps `Codex` / `AsyncCodex` / `Thread` / `Turn` and input helpers,
    but removes alias-only type layers and custom result models
    - `metadata` now returns `InitializeResponse` and `run()` returns the
    generated app-server `Turn`
    - updates docs, examples, notebook, and tests to use canonical generated
    types and regenerates `v2_all.py` against current schema
    - keeps the pinned runtime-package integration flow and real integration
    coverage
    
      ## Validation
      - `PYTHONPATH=sdk/python/src python3 -m pytest sdk/python/tests`
    - `GH_TOKEN="$(gh auth token)" RUN_REAL_CODEX_TESTS=1
    PYTHONPATH=sdk/python/src python3 -m pytest sdk/python/tests -rs`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add Python app-server SDK (#14435)
    ## TL;DR
    Bring the Python app-server SDK from `main-with-prs-13953-and-14232`
    onto current `main` as a standalone SDK-only PR.
    
    - adds the new `sdk/python` and `sdk/python-runtime` package trees
    - keeps the scope to the SDK payload only, without the unrelated
    branch-history or workflow changes from the source branch
    - regenerates `sdk/python/src/codex_app_server/generated/v2_all.py`
    against current `main` schema so the extracted SDK matches today's
    protocol definitions
    
    ## Validation
    - `PYTHONPATH=sdk/python/src python3 -m pytest sdk/python/tests`
    
    Co-authored-by: Codex <noreply@openai.com>