[6/8] Add high-level Python SDK approval mode#21910
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bfd11aa1fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| *, | ||
| approval_policy: AskForApproval | None = None, | ||
| approvals_reviewer: ApprovalsReviewer | None = None, | ||
| approval_mode: ApprovalMode = ApprovalMode.auto_review, |
There was a problem hiding this comment.
Preserve deny_all when starting turns
A caller can opt out via codex.thread_start(approval_mode=ApprovalMode.deny_all), but the returned Thread does not retain that choice. The common thread.run(...) path defaults back to auto_review and sends a turn-level override, so the first turn re-enables auto approvals instead of denying escalations. The async wrapper has the same default.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 934eda61c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| *, | ||
| approval_policy: AskForApproval | None = None, | ||
| approvals_reviewer: ApprovalsReviewer | None = None, | ||
| approval_mode: ApprovalMode = ApprovalMode.auto_review, |
There was a problem hiding this comment.
Preserve approval settings on resume
A resume with no approval argument should leave the thread's stored approval settings alone, but this default is immediately converted into approvalPolicy: on-request/approvalsReviewer: auto_review. Resuming a thread that was created with deny_all (or never outside this wrapper) silently re-enables escalated approvals. Use a sentinel/None default and only serialize an override when the caller opts in.
Useful? React with 👍 / 👎.
| *, | ||
| approval_policy: AskForApproval | None = None, | ||
| approvals_reviewer: ApprovalsReviewer | None = None, | ||
| approval_mode: ApprovalMode = ApprovalMode.auto_review, |
There was a problem hiding this comment.
Preserve approval settings on resume
A resume with no approval argument should leave the thread's stored approval settings alone, but this default is immediately converted into approvalPolicy: on-request/approvalsReviewer: auto_review. Resuming a thread that was created with deny_all silently re-enables escalated approvals. Use a sentinel/None default and only serialize an override when the caller opts in.
Useful? React with 👍 / 👎.
| *, | ||
| approval_policy: AskForApproval | None = None, | ||
| approvals_reviewer: ApprovalsReviewer | None = None, | ||
| approval_mode: ApprovalMode = ApprovalMode.auto_review, |
There was a problem hiding this comment.
Preserve approval settings when forking
Fork params describe approval fields as optional overrides for the forked thread. Because the wrapper default always serializes auto-review, forking a deny_all thread without an explicit argument changes the fork to on-request/auto_review instead of inheriting the source thread's approval behavior. This can unexpectedly re-enable escalations in the fork.
Useful? React with 👍 / 👎.
| *, | ||
| approval_policy: AskForApproval | None = None, | ||
| approvals_reviewer: ApprovalsReviewer | None = None, | ||
| approval_mode: ApprovalMode = ApprovalMode.auto_review, |
There was a problem hiding this comment.
Let turn-level approval overrides persist
Fresh evidence distinct from the earlier start-thread case: TurnStartParams.approval_policy is documented as applying to this turn and subsequent turns, but every later turn() call with the default serializes auto-review and overwrites a previous approval_mode=deny_all. A caller who denies escalations for one turn loses that protection on the next omitted-arg turn.
Useful? React with 👍 / 👎.
|
@codex review this |
78c0d5c to
7738482
Compare
f3e16de to
07c195f
Compare
|
This change is part of the following stack: Change managed by git-spice. |
## 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>
7738482 to
de4c27f
Compare
07c195f to
0521108
Compare
de4c27f to
084e40b
Compare
0521108 to
0e727fd
Compare
## 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>
## Why The Python SDK stack now depends on packaging metadata, pinned runtime wheels, generated artifacts, async behavior, and stream interleaving. Those checks need to run in CI so future changes cannot bypass the SDK test suite. ## What - Add a dedicated `python-sdk` job to `.github/workflows/sdk.yml`. - Run the job in `python:3.12-alpine` so dependency resolution exercises the pinned musl runtime wheel. - Keep the Python SDK test job parallel to the existing SDK job instead of serializing the full workflow. ## Stack 1. #21891 `[1/8]` Pin Python SDK runtime dependency 2. #21893 `[2/8]` Generate Python SDK types from pinned runtime 3. This PR `[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 - The added workflow job installs the SDK with `uv sync --extra dev --frozen` and runs the Python SDK pytest suite. --------- Co-authored-by: Codex <noreply@openai.com>
084e40b to
d0c0c48
Compare
0e727fd to
b218a24
Compare
d0c0c48 to
523854b
Compare
b218a24 to
9a3d11b
Compare
## Why The SDK package root should be the ergonomic public client API, not a dump of every generated app-server schema type. Generated models still need a supported import path, but callers should be able to tell which names are high-level SDK entrypoints and which names are protocol value models. ## What - Define a curated root `__all__` for clients, handles, input helpers, retry helpers, config, and public errors. - Add a `types` module as the supported home for generated app-server response, event, enum, and helper models. - Update docs and examples to import protocol/value models from the type module. - Add tests that lock root exports, type-module exports, star-import behavior, and example import hygiene. ## 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. This PR `[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 public API signature tests for root exports, `types` exports, and example imports. --------- Co-authored-by: Codex <noreply@openai.com>
523854b to
cdbc79c
Compare
9a3d11b to
b1bd6ed
Compare
## 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>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Expose approval_mode with deny_all and auto_review options on the high-level Python SDK, and map those choices to generated app-server approval params internally. Update examples, docs, notebooks, and public API tests to use the new mode instead of raw generated approval fields. Co-authored-by: Codex <noreply@openai.com>
Cover the exact public ApprovalMode values and ensure unsupported modes fail before sync or async high-level APIs can issue client requests. Co-authored-by: Codex <noreply@openai.com>
Default high-level thread and turn starts to auto-review, keep deny_all as the explicit opt-out, and remove the generated AskForApproval alias customization. Co-authored-by: Codex <noreply@openai.com>
Use an explicit match over ApprovalMode values while keeping a separate runtime validation error for non-enum inputs. Co-authored-by: Codex <noreply@openai.com>
Replace fake sync and async client approval tests with direct serialization checks using generated TurnStartParams, while keeping existing run-path coverage for the default behavior. Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
b1bd6ed to
24939ab
Compare
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
ApprovalModeenum withauto_reviewanddeny_all.ApprovalMode.auto_review.approval_policy/approvals_reviewerkwargs from high-level SDK wrappers.Stack
[1/8]Pin Python SDK runtime dependency[2/8]Generate Python SDK types from pinned runtime[3/8]Run Python SDK tests in CI[4/8]Define Python SDK public API surface[5/8]Rename Python SDK package toopenai-codex[6/8]Add high-level Python SDK approval mode[7/8]Add Python SDK app-server integration harness[8/8]Add Python SDK Ruff formattingVerification