…e package ## Summary This changes the Python SDK packaging model so we no longer commit `codex` binaries into `sdk/python`. Instead, published SDK builds now depend on a separate `codex-cli-bin` runtime package that carries the platform-specific `codex` binary. The SDK and runtime can be staged together with an exact version pin, so the published Python SDK still resolves to a Codex version we know is compatible. The SDK now resolves `codex` in this order: - `AppServerConfig.codex_bin` if explicitly set - installed `codex-cli-bin` runtime package There is no `PATH` fallback anymore. Published installs either use the pinned runtime or fail loudly, and local development uses an explicit `codex_bin` override when working from the repo. ## What changed - removed checked-in binaries from `sdk/python/src/codex_app_server/bin` - changed `AppServerClient` to resolve `codex` from: - explicit `AppServerConfig.codex_bin` - installed `codex-cli-bin` - kept `AppServerConfig.codex_bin` override support for local/dev use - added a new `sdk/python-runtime` package template for the pinned runtime - updated `scripts/update_sdk_artifacts.py` to stage releasable SDK/runtime packages instead of downloading binaries into the repo - made `codex-cli-bin` build as a platform-specific wheel - made `codex-cli-bin` wheel-only by rejecting `sdist` builds - updated docs/tests to match the new packaging flow and explicit local-dev contract ## Why Checking in six platform binaries made the repo much heavier and tied normal source changes to release artifacts. This keeps the compatibility guarantees we want, but moves them into packaging: - the published SDK can depend on an exact `codex-cli-bin==...` - the runtime package carries the platform-specific binary - users still get a pinned runtime - the repo no longer needs to store those binaries It also makes the runtime contract stricter and more predictable: - published installs never silently fall back to an arbitrary `codex` on `PATH` - local development remains supported through explicit `codex_bin` - `codex-cli-bin` is distributed as platform wheels only, which avoids unsafe source-distribution installs for a package that embeds a prebuilt binary ## Validation - ran targeted Python SDK tests: - `python3 -m pytest sdk/python/tests/test_artifact_workflow_and_binaries.py sdk/python/tests/test_client_rpc_methods.py sdk/python/tests/test_contract_generation.py` - exercised the staging flow with a local dummy binary to verify SDK/runtime staging end to end - verified the staged runtime package builds a platform-specific wheel (`Root-Is-Purelib: false`) rather than a universal `py3-none-any` wheel - added test coverage for the explicit-only runtime resolution model - added test coverage that `codex-cli-bin` rejects `sdist` builds --------- Co-authored-by: sdcoffey <stevendcoffey@gmail.com>
2.7 KiB
FAQ
Thread vs turn
- A
Threadis conversation state. - A
Turnis one model execution inside that thread. - Multi-turn chat means multiple turns on the same
Thread.
run() vs stream()
Turn.run()is the easiest path. It consumes events until completion and returnsTurnResult.Turn.stream()yields raw notifications (Notification) so you can react event-by-event.
Choose run() for most apps. Choose stream() for progress UIs, custom timeout logic, or custom parsing.
Sync vs async clients
Codexis the minimal sync SDK and best default.AsyncAppServerClientwraps the sync transport withasyncio.to_thread(...)for async-friendly call sites.
If your app is not already async, stay with Codex.
thread(...) vs thread_resume(...)
codex.thread(thread_id)only binds a local helper to an existing thread ID.codex.thread_resume(thread_id, ...)performs athread/resumeRPC and can apply overrides (model, instructions, sandbox, etc.).
Use thread(...) for simple continuation. Use thread_resume(...) when you need explicit resume semantics or override fields.
Why does constructor fail?
Codex() is eager: it starts transport and calls initialize in __init__.
Common causes:
- published runtime package (
codex-cli-bin) is not installed - local
codex_binoverride points to a missing file - 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:
cd sdk/python
python scripts/update_sdk_artifacts.py generate-types
python scripts/update_sdk_artifacts.py \
stage-sdk \
/tmp/codex-python-release/codex-app-server-sdk \
--runtime-version 1.2.3
python scripts/update_sdk_artifacts.py \
stage-runtime \
/tmp/codex-python-release/codex-cli-bin \
/path/to/codex \
--runtime-version 1.2.3
Why does a turn "hang"?
A turn is complete only when turn/completed arrives for that turn ID.
run()waits for this automatically.- With
stream(), make sure you keep consuming notifications until completion.
How do I retry safely?
Use retry_on_overload(...) for transient overload failures (ServerBusyError).
Do not blindly retry all errors. For InvalidParamsError or MethodNotFoundError, fix inputs/version compatibility instead.
Common pitfalls
- Starting a new thread for every prompt when you wanted continuity.
- Forgetting to
close()(or not usingwith Codex() as codex:). - Ignoring
TurnResult.statusandTurnResult.error. - Mixing SDK input classes with raw dicts incorrectly in minimal API paths.