Commit Graph

2284 Commits

  • Preempt mailbox mail after reasoning/commentary items (#16725)
    Send pending mailbox mail after completed reasoning or commentary items
    so follow-up requests can pick it up mid-turn.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] allow disabling environment context injection (#16745)
    This adds an `include_environment_context` config/profile flag that
    defaults on, and guards both initial injection and later environment
    updates to allow skipping injection of `<environment_context>`.
  • [codex] allow disabling prompt instruction blocks (#16735)
    This PR adds root and profile config switches to omit the generated
    `<permissions instructions>` and `<apps_instructions>` prompt blocks
    while keeping both enabled by default, and it gates both the initial
    developer-context injection and later permissions diff injection so
    turning the permissions block off stays effective across turn-context
    overrides.
    
    Also added a prompt debug tool that can be used as `codex debug
    prompt-input "hello"` and dumps the constructed items list.
  • Remove OPENAI_BASE_URL config fallback (#16720)
    The `OPENAI_BASE_URL` environment variable has been a significant
    support issue, so we decided to deprecate it in favor of an
    `openai_base_url` config key. We've had the deprecation warning in place
    for about a month, so users have had time to migrate to the new
    mechanism. This PR removes support for `OPENAI_BASE_URL` entirely.
  • Fix Windows Bazel app-server trust tests (#16711)
    ## Why
    
    Extracted from [#16528](https://github.com/openai/codex/pull/16528) so
    the Windows Bazel app-server test failures can be reviewed independently
    from the rest of that PR.
    
    This PR targets:
    
    -
    `suite::v2::thread_shell_command::thread_shell_command_runs_as_standalone_turn_and_persists_history`
    -
    `suite::v2::thread_start::thread_start_with_elevated_sandbox_trusts_project_and_followup_loads_project_config`
    -
    `suite::v2::thread_start::thread_start_with_nested_git_cwd_trusts_repo_root`
    
    There were two Windows-specific assumptions baked into those tests and
    the underlying trust lookup:
    
    - project trust keys were persisted and looked up using raw path
    strings, but Bazel's Windows test environment can surface canonicalized
    paths with `\\?\` / UNC prefixes or normalized symlink/junction targets,
    so follow-up `thread/start` requests no longer matched the project entry
    that had just been written
    - `item/commandExecution/outputDelta` assertions compared exact trailing
    line endings even though shell output chunk boundaries and CRLF handling
    can differ on Windows, and Bazel made that timing-sensitive mismatch
    visible
    
    There was also one behavior bug separate from the assertion cleanup:
    `thread/start` decided whether to persist trust from the final resolved
    sandbox policy, but on Windows an explicit `workspace-write` request may
    be downgraded to `read-only`. That incorrectly skipped writing trust
    even though the request had asked to elevate the project, so the new
    logic also keys off the requested sandbox mode.
    
    ## What
    
    - Canonicalize project trust keys when persisting/loading `[projects]`
    entries, while still accepting legacy raw keys for existing configs.
    - Persist project trust when `thread/start` explicitly requests
    `workspace-write` or `danger-full-access`, even if the resolved policy
    is later downgraded on Windows.
    - Make the Windows app-server tests compare persisted trust paths and
    command output deltas in a path/newline-normalized way.
    
    ## Verification
    
    - Existing app-server v2 tests cover the three failing Windows Bazel
    cases above.
  • Sanitize forked child history (#16709)
    - Keep only parent system/developer/user messages plus assistant
    final-answer messages in forked child history.
    - Strip parent tool/reasoning items and remove the unmatched synthetic
    spawn output.
  • fix: preserve platform-specific core shell env vars (#16707)
    ## Why
    
    We were seeing failures in the following tests as part of trying to get
    all the tests running under Bazel on Windows in CI
    (https://github.com/openai/codex/pull/16528):
    
    ```
    suite::shell_command::unicode_output::with_login
    suite::shell_command::unicode_output::without_login
    ```
    
    Certainly `PATHEXT` should have been included in the extra `CORE_VARS`
    list, so we fix that up here, but also take things a step further for
    now by forcibly ensuring it is set on Windows in the return value of
    `create_env()`. Once we get the Windows Bazel build working reliably
    (i.e., after #16528 is merged), we should come back to this and confirm
    we can remove the special case in `create_env()`.
    
    ## What
    
    - Split core env inheritance into `COMMON_CORE_VARS` plus
    platform-specific allowlists for Windows and Unix in
    [`exec_env.rs`](https://github.com/openai/codex/blob/1b55c88fbf585b32cd553cb9d02ec817f2ad6ebc/codex-rs/core/src/exec_env.rs#L45-L81).
    - Preserve `PATHEXT`, `USERNAME`, and `USERPROFILE` on Windows, and
    `HOME` / locale vars on Unix.
    - Backfill a default `PATHEXT` in `create_env()` on Windows if the
    parent env does not provide one, so child process launch still works in
    stripped-down Bazel environments.
    - Extend the Windows exec-env test to assert mixed-case `PathExt`
    survives case-insensitive core filtering, and document why the
    shell-command Unicode test goes through a child process.
    
    ## Verification
    
    - `cargo test -p codex-core exec_env::tests`
  • remove temporary ownership re-exports (#16626)
    Stacked on #16508.
    
    This removes the temporary `codex-core` / `codex-login` re-export shims
    from the ownership split and rewrites callsites to import directly from
    `codex-model-provider-info`, `codex-models-manager`, `codex-api`,
    `codex-protocol`, `codex-feedback`, and `codex-response-debug-context`.
    
    No behavior change intended; this is the mechanical import cleanup layer
    split out from the ownership move.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • extract models manager and related ownership from core (#16508)
    ## Summary
    - split `models-manager` out of `core` and add `ModelsManagerConfig`
    plus `Config::to_models_manager_config()` so model metadata paths stop
    depending on `core::Config`
    - move login-owned/auth-owned code out of `core` into `codex-login`,
    move model provider config into `codex-model-provider-info`, move API
    bridge mapping into `codex-api`, move protocol-owned types/impls into
    `codex-protocol`, and move response debug helpers into a dedicated
    `response-debug-context` crate
    - move feedback tag emission into `codex-feedback`, relocate tests to
    the crates that now own the code, and keep broad temporary re-exports so
    this PR avoids a giant import-only rewrite
    
    ## Major moves and decisions
    - created `codex-models-manager` as the owner for model
    cache/catalog/config/model info logic, including the new
    `ModelsManagerConfig` struct
    - created `codex-model-provider-info` as the owner for provider config
    parsing/defaults and kept temporary `codex-login`/`codex-core`
    re-exports for old import paths
    - moved `api_bridge` error mapping + `CoreAuthProvider` into
    `codex-api`, while `codex-login::api_bridge` temporarily re-exports
    those symbols and keeps the `auth_provider_from_auth` wrapper
    - moved `auth_env_telemetry` and `provider_auth` ownership to
    `codex-login`
    - moved `CodexErr` ownership to `codex-protocol::error`, plus
    `StreamOutput`, `bytes_to_string_smart`, and network policy helpers to
    protocol-owned modules
    - created `codex-response-debug-context` for
    `extract_response_debug_context`, `telemetry_transport_error_message`,
    and related response-debug plumbing instead of leaving that behavior in
    `core`
    - moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and
    `emit_feedback_request_tags_with_auth_env` to `codex-feedback`
    - deferred removal of temporary re-exports and the mechanical import
    rewrites to a stacked follow-up PR so this PR stays reviewable
    
    ## Test moves
    - moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to
    `login/tests/suite/auth_refresh.rs`
    - moved text encoding coverage from
    `core/tests/suite/text_encoding_fix.rs` to
    `protocol/src/exec_output_tests.rs`
    - moved model info override coverage from
    `core/tests/suite/model_info_overrides.rs` to
    `models-manager/src/model_info_overrides_tests.rs`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • test: use cmd.exe for ProviderAuthScript on Windows (#16629)
    ## Why
    
    The Windows `ProviderAuthScript` test helpers do not need PowerShell.
    Running them through `cmd.exe` is enough to emit the next fixture token
    and rotate `tokens.txt`, and it avoids a PowerShell-specific dependency
    in these tests.
    
    ## What changed
    
    - Replaced the Windows `print-token.ps1` fixtures with `print-token.cmd`
    in `codex-rs/core/src/models_manager/manager_tests.rs` and
    `codex-rs/login/src/auth/auth_tests.rs`.
    - Switched the failing external-auth helper in
    `codex-rs/login/src/auth/auth_tests.rs` from `powershell.exe -Command
    'exit 1'` to `cmd.exe /d /s /c 'exit /b 1'`.
    - Updated Windows timeout comments so they no longer call out PowerShell
    specifically.
    
    ## Verification
    
    - `cargo test -p codex-login`
    - `cargo test -p codex-core` (fails in unrelated
    `core/src/config/config_tests.rs` assertions in this checkout)
  • core: cut codex-core compile time 48% with native async SessionTask (#16631)
    ## Why
    
    This continues the compile-time cleanup from #16630. `SessionTask`
    implementations are monomorphized, but `Session` stores the task behind
    a `dyn` boundary so it can drive and abort heterogenous turn tasks
    uniformly. That means we can move the `#[async_trait]` expansion off the
    implementation trait, keep a small boxed adapter only at the storage
    boundary, and preserve the existing task lifecycle semantics while
    reducing the amount of generated async-trait glue in `codex-core`.
    
    One measurement caveat showed up while exploring this: a warm
    incremental benchmark based on `touch core/src/tasks/mod.rs && cargo
    check -p codex-core --lib` was basically flat, but that was the wrong
    benchmark for this change. Using package-clean `codex-core` rebuilds,
    like #16630, shows the real win.
    
    Relevant pre-change code:
    
    - [`SessionTask` with
    `#[async_trait]`](https://github.com/openai/codex/blob/3c7f013f9735e67796c70d95f75f436b7f97e3ec/codex-rs/core/src/tasks/mod.rs#L129-L182)
    - [`RunningTask` storing `Arc<dyn
    SessionTask>`](https://github.com/openai/codex/blob/3c7f013f9735e67796c70d95f75f436b7f97e3ec/codex-rs/core/src/state/turn.rs#L69-L77)
    
    ## What changed
    
    - Switched `SessionTask::{run, abort}` to native RPITIT futures with
    explicit `Send` bounds.
    - Added a private `AnySessionTask` adapter that boxes those futures only
    at the `Arc<dyn ...>` storage boundary.
    - Updated `RunningTask` to store `Arc<dyn AnySessionTask>` and removed
    `#[async_trait]` from the concrete task impls plus test-only
    `SessionTask` impls.
    
    ## Timing
    
    Benchmarked package-clean `codex-core` rebuilds with dependencies left
    warm:
    
    ```shell
    cargo check -p codex-core --lib >/dev/null
    cargo clean -p codex-core >/dev/null
    /usr/bin/time -p cargo +nightly rustc -p codex-core --lib -- \
      -Z time-passes \
      -Z time-passes-format=json >/dev/null
    ```
    
    | revision | rustc `total` | process `real` | `generate_crate_metadata`
    | `MIR_borrow_checking` | `monomorphization_collector_graph_walk` |
    | --- | ---: | ---: | ---: | ---: | ---: |
    | parent `3c7f013f9735` | 67.21s | 67.71s | 24.61s | 23.43s | 22.43s |
    | this PR `2cafd783ac22` | 35.08s | 35.60s | 8.01s | 7.25s | 7.15s |
    | delta | -47.8% | -47.4% | -67.5% | -69.1% | -68.1% |
    
    For completeness, the warm touched-file benchmark stayed flat (`1.96s`
    parent vs `1.97s` this PR), which is why that benchmark should not be
    used to evaluate this refactor.
    
    ## Verification
    
    - Ran `cargo test -p codex-core`; this change compiled and task-related
    tests passed before hitting the same unrelated 5
    `config::tests::*guardian*` failures already present on the parent
    stack.
  • core: cut codex-core compile time 63% with native async ToolHandler (#16630)
    ## Why
    
    `ToolHandler` was still paying a large compile-time tax from
    `#[async_trait]` on every concrete handler impl, even though the only
    object-safe boundary the registry actually stores is the internal
    `AnyToolHandler` adapter.
    
    This PR removes that macro-generated async wrapper layer from concrete
    `ToolHandler` impls while keeping the existing object-safe shim in
    `AnyToolHandler`. In practice, that gets essentially the same
    compile-time win as the larger type-erasure refactor in #16627, but with
    a much smaller diff and without changing the public shape of
    `ToolHandler<Output = T>`.
    
    That tradeoff matters here because this is a broad `codex-core` hotspot
    and reviewers should be able to judge the compile-time impact from hard
    numbers, not vibes.
    
    ## Headline result
    
    On a clean `codex-core` package rebuild (`cargo clean -p codex-core`
    before each command), rustc `total` dropped from **187.15s to 68.98s**
    versus the shared `0bd31dc382bd` baseline: **-63.1%**.
    
    The biggest hot passes dropped by roughly **71-72%**:
    
    | Metric | Baseline `0bd31dc382bd` | This PR `41f7ac0adeac` | Delta |
    |---|---:|---:|---:|
    | `total` | 187.15s | 68.98s | **-63.1%** |
    | `generate_crate_metadata` | 84.53s | 24.49s | **-71.0%** |
    | `MIR_borrow_checking` | 84.13s | 24.58s | **-70.8%** |
    | `monomorphization_collector_graph_walk` | 79.74s | 22.19s | **-72.2%**
    |
    | `evaluate_obligation` self-time | 180.62s | 46.91s | **-74.0%** |
    
    Important caveat: `-Z time-passes` timings are nested, so
    `generate_crate_metadata` and `monomorphization_collector_graph_walk`
    are mostly overlapping, not additive.
    
    ## Why this PR over #16627
    
    #16627 already proved that the `ToolHandler` stack was the right
    hotspot, but it got there by making `ToolHandler` object-safe and
    changing every handler to return `BoxFuture<Result<AnyToolResult, _>>`
    directly.
    
    This PR keeps the lower-churn shape:
    
    - `ToolHandler` remains generic over `type Output`.
    - Concrete handlers use native RPITIT futures with explicit `Send`
    bounds.
    - `AnyToolHandler` remains the only object-safe adapter and still does
    the boxing at the registry boundary, as before.
    - The implementation diff is only **33 files, +28/-77**.
    
    The measurements are at least comparable, and in this run this PR is
    slightly faster than #16627 on the pass-level total:
    
    | Metric | #16627 | This PR | Delta |
    |---|---:|---:|---:|
    | `total` | 79.90s | 68.98s | **-13.7%** |
    | `generate_crate_metadata` | 25.88s | 24.49s | **-5.4%** |
    | `monomorphization_collector_graph_walk` | 23.54s | 22.19s | **-5.7%**
    |
    | `evaluate_obligation` self-time | 43.29s | 46.91s | +8.4% |
    
    ## Profile data
    
    ### Crate-level timings
    
    `cargo +nightly build -p codex-core --lib -Z unstable-options
    --timings=json` after `cargo clean -p codex-core`.
    
    Baseline data below is reused from the shared parent `0bd31dc382bd`
    profile because this PR and #16627 are both one commit on top of that
    same parent.
    
    | Crate | Baseline `duration` | This PR `duration` | Delta | Baseline
    `rmeta_time` | This PR `rmeta_time` | Delta |
    |---|---:|---:|---:|---:|---:|---:|
    | `codex_core` | 187.380776583s | 69.171113833s | **-63.1%** |
    174.474507208s | 55.873015583s | **-68.0%** |
    | `starlark` | 17.90s | 16.773824125s | -6.3% | n/a | 8.8999965s | n/a |
    
    ### Pass-level timings
    
    `cargo +nightly rustc -p codex-core --lib -- -Z time-passes -Z
    time-passes-format=json` after `cargo clean -p codex-core`.
    
    | Pass | Baseline | This PR | Delta |
    |---|---:|---:|---:|
    | `total` | 187.150662083s | 68.978770375s | **-63.1%** |
    | `generate_crate_metadata` | 84.531864625s | 24.487462958s | **-71.0%**
    |
    | `MIR_borrow_checking` | 84.131389375s | 24.575553875s | **-70.8%** |
    | `monomorphization_collector_graph_walk` | 79.737515042s |
    22.190207417s | **-72.2%** |
    | `codegen_crate` | 12.362532292s | 12.695237625s | +2.7% |
    | `type_check_crate` | 4.4765405s | 5.442019542s | +21.6% |
    | `coherence_checking` | 3.311121208s | 4.239935292s | +28.0% |
    | process `real` / `user` / `sys` | 187.70s / 201.87s / 4.99s | 69.52s /
    85.90s / 2.92s | n/a |
    
    ### Self-profile query summary
    
    `cargo +nightly rustc -p codex-core --lib -- -Z self-profile=... -Z
    self-profile-events=default,query-keys,args,llvm,artifact-sizes` after
    `cargo clean -p codex-core`, summarized with `measureme summarize -p
    0.5`.
    
    | Query / phase | Baseline self time | This PR self time | Delta |
    Baseline total time | This PR total time | Baseline item count | This PR
    item count | Baseline cache hits | This PR cache hits |
    |---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
    | `evaluate_obligation` | 180.62s | 46.91s | **-74.0%** | 182.08s |
    48.37s | 572,234 | 388,659 | 1,130,998 | 1,058,553 |
    | `mir_borrowck` | 1.42s | 1.49s | +4.9% | 93.77s | 29.59s | n/a | 6,184
    | n/a | 15,298 |
    | `typeck` | 1.84s | 1.87s | +1.6% | 2.38s | 2.44s | n/a | 9,367 | n/a |
    79,247 |
    | `LLVM_module_codegen_emit_obj` | n/a | 17.12s | n/a | 17.01s | 17.12s
    | n/a | 256 | n/a | 0 |
    | `LLVM_passes` | n/a | 13.07s | n/a | 12.95s | 13.07s | n/a | 1 | n/a |
    0 |
    | `codegen_module` | n/a | 12.33s | n/a | 12.22s | 13.64s | n/a | 256 |
    n/a | 0 |
    | `items_of_instance` | n/a | 676.00ms | n/a | n/a | 24.96s | n/a |
    99,990 | n/a | 0 |
    | `type_op_prove_predicate` | n/a | 660.79ms | n/a | n/a | 24.78s | n/a
    | 78,762 | n/a | 235,877 |
    
    | Summary | Baseline | This PR |
    |---|---:|---:|
    | `evaluate_obligation` % of total CPU | 70.821% | 38.880% |
    | self-profile total CPU time | 255.042999997s | 120.661175956s |
    | process `real` / `user` / `sys` | 220.96s / 235.02s / 7.09s | 86.35s /
    103.66s / 3.54s |
    
    ### Artifact sizes
    
    From the same `measureme summarize` output:
    
    | Artifact | Baseline | This PR | Delta |
    |---|---:|---:|---:|
    | `crate_metadata` | 26,534,471 bytes | 26,545,248 bytes | +10,777 |
    | `dep_graph` | 253,181,425 bytes | 239,240,806 bytes | -13,940,619 |
    | `linked_artifact` | 565,366,624 bytes | 562,673,176 bytes | -2,693,448
    |
    | `object_file` | 513,127,264 bytes | 510,464,096 bytes | -2,663,168 |
    | `query_cache` | 137,440,945 bytes | 136,982,566 bytes | -458,379 |
    | `cgu_instructions` | 3,586,307 bytes | 3,575,121 bytes | -11,186 |
    | `codegen_unit_size_estimate` | 2,084,846 bytes | 2,078,773 bytes |
    -6,073 |
    | `work_product_index` | 19,565 bytes | 19,565 bytes | 0 |
    
    ### Baseline hotspots before this change
    
    These are the top normalized obligation buckets from the shared baseline
    profile:
    
    | Obligation bucket | Samples | Duration |
    |---|---:|---:|
    | `outlives:tasks::review::ReviewTask` | 1,067 | 6.33s |
    | `outlives:tools::handlers::unified_exec::UnifiedExecHandler` | 896 |
    5.63s |
    | `trait:T as tools::registry::ToolHandler` | 876 | 5.45s |
    | `outlives:tools::handlers::shell::ShellHandler` | 888 | 5.37s |
    | `outlives:tools::handlers::shell::ShellCommandHandler` | 870 | 5.29s |
    |
    `outlives:tools::runtimes::shell::unix_escalation::CoreShellActionProvider`
    | 637 | 3.73s |
    | `outlives:tools::handlers::mcp::McpHandler` | 695 | 3.61s |
    | `outlives:tasks::regular::RegularTask` | 726 | 3.57s |
    
    Top `items_of_instance` entries before this change were mostly concrete
    async handler/task impls:
    
    | Instance | Duration |
    |---|---:|
    | `tasks::regular::{impl#2}::run` | 3.79s |
    | `tools::handlers::mcp::{impl#0}::handle` | 3.27s |
    | `tools::runtimes::shell::unix_escalation::{impl#2}::determine_action`
    | 3.09s |
    | `tools::handlers::agent_jobs::{impl#11}::handle` | 3.07s |
    | `tools::handlers::multi_agents::spawn::{impl#1}::handle` | 2.84s |
    | `tasks::review::{impl#4}::run` | 2.82s |
    | `tools::handlers::multi_agents_v2::spawn::{impl#2}::handle` | 2.80s |
    | `tools::handlers::multi_agents::resume_agent::{impl#1}::handle` |
    2.73s |
    | `tools::handlers::unified_exec::{impl#2}::handle` | 2.54s |
    | `tasks::compact::{impl#4}::run` | 2.45s |
    
    ## What changed
    
    Relevant pre-change registry shape:
    [`codex-rs/core/src/tools/registry.rs`](https://github.com/openai/codex/blob/0bd31dc382bd1c33dc2bb6b97069c76aa10ba14b/codex-rs/core/src/tools/registry.rs#L38-L219)
    
    Current registry shape in this PR:
    [`codex-rs/core/src/tools/registry.rs`](https://github.com/openai/codex/blob/41f7ac0adeac81d667541853d6546267d6083613/codex-rs/core/src/tools/registry.rs#L38-L203)
    
    - `ToolHandler::{is_mutating, handle}` now return native `impl Future +
    Send` futures instead of using `#[async_trait]`.
    - `AnyToolHandler` remains the object-safe adapter and boxes those
    futures at the registry boundary with explicit lifetimes.
    - Concrete handlers and the registry test handler drop `#[async_trait]`
    but otherwise keep their async method bodies intact.
    - Representative examples:
    [`codex-rs/core/src/tools/handlers/shell.rs`](https://github.com/openai/codex/blob/41f7ac0adeac81d667541853d6546267d6083613/codex-rs/core/src/tools/handlers/shell.rs#L223-L379),
    [`codex-rs/core/src/tools/handlers/unified_exec.rs`](https://github.com/openai/codex/blob/41f7ac0adeac81d667541853d6546267d6083613/codex-rs/core/src/tools/handlers/unified_exec.rs),
    [`codex-rs/core/src/tools/registry_tests.rs`](https://github.com/openai/codex/blob/41f7ac0adeac81d667541853d6546267d6083613/codex-rs/core/src/tools/registry_tests.rs)
    
    ## Tradeoff
    
    This is intentionally less invasive than #16627: it does **not** move
    result boxing into every concrete handler and does **not** change
    `ToolHandler` into an object-safe trait.
    
    Instead, it keeps the existing registry-level type-erasure boundary and
    only removes the macro-generated async wrapper layer from concrete
    impls. So the runtime boxing story stays basically the same as before,
    while the compile-time savings are still large.
    
    ## Verification
    
    Existing verification for this branch still applies:
    
    - Ran `cargo test -p codex-core`; this change compiled and the suite
    reached the known unrelated `config::tests::*guardian*` failures, with
    no local diff under `codex-rs/core/src/config/`.
    
    Profiling commands used for the tables above:
    
    - `cargo clean -p codex-core`
    - `cargo +nightly build -p codex-core --lib -Z unstable-options
    --timings=json`
    - `cargo +nightly rustc -p codex-core --lib -- -Z time-passes -Z
    time-passes-format=json`
    - `cargo +nightly rustc -p codex-core --lib -- -Z self-profile=... -Z
    self-profile-events=default,query-keys,args,llvm,artifact-sizes`
    - `measureme summarize -p 0.5`
  • fix: add shell fallback paths for pwsh/powershell that work on GitHub Actions Windows runners (#16617)
    Recently, I merged a number of PRs to increase startup timeouts for
    scripts that ran under PowerShell, but in the failure for
    `suite::codex_tool::test_shell_command_approval_triggers_elicitation`, I
    found this in the error logs when running on Bazel with BuildBuddy:
    
    ```
    [mcp stderr] 2026-04-02T19:54:10.758951Z ERROR codex_core::tools::router: error=Exit code: 1
    [mcp stderr] Wall time: 0.2 seconds
    [mcp stderr] Output:
    [mcp stderr] 'New-Item' is not recognized as an internal or external command,
    [mcp stderr] operable program or batch file.
    [mcp stderr] 
    ```
    
    This error implies that the command was run under `cmd.exe` instead of
    `pwsh.exe`. Under GitHub Actions, I suspect that the `%PATH%` that is
    passed to our Bazel builder is scrubbed such that our tests cannot find
    PowerShell where GitHub installs it. Having these explicit fallback
    paths should help.
    
    While we could enable these only for tests, I don't see any harm in
    keeping them in production, as well.
  • [codex] Remove codex-core config type shim (#16529)
    ## Why
    
    This finishes the config-type move out of `codex-core` by removing the
    temporary compatibility shim in `codex_core::config::types`. Callers now
    depend on `codex-config` directly, which keeps these config model types
    owned by the config crate instead of re-expanding `codex-core` as a
    transitive API surface.
    
    ## What Changed
    
    - Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
    `core::config::ApprovalsReviewer` re-export.
    - Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
    `codex-mcp-server`, and `codex-linux-sandbox` call sites to import
    `codex_config::types` directly.
    - Added explicit `codex-config` dependencies to downstream crates that
    previously relied on the `codex-core` re-export.
    - Regenerated `codex-rs/core/config.schema.json` after updating the
    config docs path reference.
  • fix: move some test utilities out of codex-rs/core/src/tools/spec.rs (#16524)
    The `#[cfg(test)]` in `codex-rs/core/src/tools/spec.rs` smelled funny to
    me and it turns out these members were straightforward to move.
  • [codex] Move config types into codex-config (#16523)
    ## Why
    
    `codex-rs/core/src/config/types.rs` is a plain config-type module with
    no dependency on `codex-core`. Moving it into `codex-config` shrinks the
    core crate and gives config-only consumers a more natural dependency
    boundary.
    
    ## What Changed
    
    - Added `codex_config::types` with the moved structs, enums, constants,
    and unit tests.
    - Kept `codex_core::config::types` as a compatibility re-export to avoid
    a broad call-site migration in this PR.
    - Switched notice-table writes in `core/src/config/edit.rs` to a local
    `NOTICE_TABLE_KEY` constant.
    - Added the `wildmatch` runtime dependency and `tempfile` test
    dependency to `codex-config`.
  • Move tool registry plan tests into codex-tools (#16521)
    ## Why
    
    #16513 moved pure tool-registry planning into `codex-tools`, but much of
    the corresponding spec/feature-gating coverage still lived in
    `codex-core`. That leaves the tests for planner behavior in the crate
    that no longer owns that logic and makes the next extraction steps
    harder to review.
    
    ## What
    
    Move the planner-only `spec_tests.rs` coverage into
    `codex-rs/tools/src/tool_registry_plan_tests.rs` and wire it up from
    `codex-rs/tools/src/tool_registry_plan.rs` using the crate-local `#[path
    = "tool_registry_plan_tests.rs"] mod tests;` pattern.
    
    The `codex-core` test file now keeps the core-side integration checks:
    router-visible model tool lists, namespaced handler alias registration,
    shell adapter behavior, and MCP schema edge cases that still exercise
    the `core` binding layer.
    
    ## Verification
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract tool registry planning into codex-tools (#16513)
    ## Why
    This is a larger step in the `codex-core` -> `codex-tools` migration
    called out in `AGENTS.md`.
    
    `codex-rs/core/src/tools/spec.rs` had become mostly pure tool-spec
    assembly plus handler registration. That made it hard to move more of
    the tool-definition layer into `codex-tools`, because the runtime
    binding and the crate-independent planning logic were still interleaved
    in one function.
    
    Splitting those concerns gives `codex-tools` ownership of the
    declarative registry plan while keeping `codex-core` responsible for
    instantiating concrete handlers.
    
    ## What Changed
    - Add a `codex-tools` registry-plan layer in
    `codex-rs/tools/src/tool_registry_plan.rs` and
    `codex-rs/tools/src/tool_registry_plan_types.rs`.
    - Move feature-gated tool-spec assembly, MCP/dynamic tool conversion,
    tool-search aliases, and code-mode nested-plan expansion into
    `codex-tools`.
    - Keep `codex-rs/core/src/tools/spec.rs` as the core-side adapter that
    maps each planned handler kind to concrete runtime handler instances.
    - Update `spec_tests.rs` to import the moved `codex_tools` symbols
    directly instead of relying on top-level `spec.rs` re-exports.
    
    This is intended to be a straight refactor with no behavior change and
    no new test surface.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16513).
    * #16521
    * __->__ #16513
  • core: remove cross-crate re-exports from lib.rs (#16512)
    ## Why
    
    `codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
    which made downstream crates depend on `codex-core` as a proxy module
    instead of the actual owner crate.
    
    Removing those forwards makes crate boundaries explicit and lets leaf
    crates drop unnecessary `codex-core` dependencies. In this PR, this
    reduces the dependency on `codex-core` to `codex-login` in the following
    files:
    
    ```
    codex-rs/backend-client/Cargo.toml
    codex-rs/mcp-server/tests/common/Cargo.toml
    ```
    
    ## What
    
    - Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
    `codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
    `codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
    `codex-tools`, and `codex-utils-path`.
    - Delete the `default_client` forwarding shim in `codex-rs/core`.
    - Update in-crate and downstream callsites to import directly from the
    owning `codex-*` crate.
    - Add direct Cargo dependencies where callsites now target the owner
    crate, and remove `codex-core` from `codex-rs/backend-client`.
  • Extract code-mode nested tool collection into codex-tools (#16509)
    ## Why
    This is another small step in the `codex-core` -> `codex-tools`
    migration described in `AGENTS.md`.
    
    `core/src/tools/spec.rs` and `core/src/tools/code_mode/mod.rs` were both
    hand-rolling the same pure transformation: convert visible `ToolSpec`s
    into code-mode nested tool definitions, then sort and deduplicate by
    tool name. That logic does not depend on core runtime state or handlers,
    so keeping it in `codex-core` makes `spec.rs` harder to peel out later
    than it needs to be.
    
    ## What Changed
    - Add `collect_code_mode_tool_definitions()` to
    `codex-rs/tools/src/code_mode.rs`.
    - Reuse that helper from `codex-rs/core/src/tools/spec.rs` when
    assembling the `exec` tool description.
    - Reuse the same helper from `codex-rs/core/src/tools/code_mode/mod.rs`
    when exposing nested tool metadata to the code-mode runtime.
    
    This is intended to be a straight refactor with no behavior change and
    no new test surface.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    - `cargo test -p codex-core code_mode_only_`
  • core: use codex-mcp APIs directly (#16510)
    ## Why
    
    `codex-mcp` already owns the shared MCP API surface, including `auth`,
    `McpConfig`, `CODEX_APPS_MCP_SERVER_NAME`, and tool-name helpers in
    [`codex-rs/codex-mcp/src/mcp/mod.rs`](https://github.com/openai/codex/blob/f61e85dbfb5373cde6827d232ac8ea447c237e81/codex-rs/codex-mcp/src/mcp/mod.rs#L1-L35).
    Re-exporting that surface from `codex_core::mcp` gives downstream crates
    two import paths for the same API and hides the real crate dependency.
    
    This PR keeps `codex_core::mcp` focused on the local `McpManager`
    wrapper in
    [`codex-rs/core/src/mcp.rs`](https://github.com/openai/codex/blob/f61e85dbfb5373cde6827d232ac8ea447c237e81/codex-rs/core/src/mcp.rs#L13-L40)
    and makes consumers import shared MCP APIs from `codex_mcp` directly.
    
    ## What
    
    - Remove the `codex_mcp::mcp` re-export surface from `core/src/mcp.rs`.
    - Update `codex-core` internals plus `codex-app-server`, `codex-cli`,
    and `codex-tui` test code to import MCP APIs from `codex_mcp::mcp`
    directly.
    - Add explicit `codex-mcp` dependencies where those crates now use that
    API surface, and refresh `Cargo.lock`.
    
    ## Verification
    
    - `just bazel-lock-check`
    - `cargo test -p codex-core -p codex-cli -p codex-tui`
      - `codex-cli` passed.
    - `codex-core` still fails five unrelated config tests in
    `core/src/config/config_tests.rs` (`approvals_reviewer_*` and
    `smart_approvals_alias_*`).
    - A broader `cargo test -p codex-core -p codex-app-server -p codex-cli
    -p codex-tui` run previously hung in `codex-app-server` test
    `in_process_start_uses_requested_session_source_for_thread_start`.
  • Extract request_user_input normalization into codex-tools (#16503)
    ## Why
    This is another incremental step in the `codex-core` -> `codex-tools`
    migration called out in `AGENTS.md`: keep pure tool-definition and
    wire-shaping logic out of `codex-core` so the core crate can stay
    focused on runtime orchestration.
    
    `request_user_input` already had its spec and mode-availability helpers
    in `codex-tools` after #16471. The remaining argument validation and
    normalization still lived in the core runtime handler, which left that
    tool split across the two crates.
    
    ## What Changed
    - Export `REQUEST_USER_INPUT_TOOL_NAME` and
    `normalize_request_user_input_args()` from
    `codex-rs/tools/src/request_user_input_tool.rs`.
    - Use that `codex-tools` surface from `codex-rs/core/src/tools/spec.rs`
    and `codex-rs/core/src/tools/handlers/request_user_input.rs`.
    - Keep the core handler responsible for payload parsing, session
    dispatch, cancellation handling, and response serialization.
    
    This is intended to be a straight refactor with no behavior change.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core request_user_input`
  • core: use codex-tools config types directly (#16504)
    ## Why
    
    `codex-rs/tools/src/lib.rs` already defines the [canonical `codex_tools`
    export
    surface](https://github.com/openai/codex/blob/bf081b9e286e620d25c1d61cf0f38f74a0f982ce/codex-rs/tools/src/lib.rs#L83-L88)
    for `ToolsConfig`, `ToolsConfigParams`, and the shell backend config
    types. Re-exporting those same types from `core/src/tools/spec.rs` gives
    `codex-core` two import paths for one API and blurs which crate owns
    those config definitions.
    
    This PR removes that duplicate path so `codex-core` callsites depend on
    `codex_tools` directly.
    
    ## What
    
    - Remove the five `codex_tools` re-exports from
    `core/src/tools/spec.rs`.
    - Update `codex-core` production and test callsites to import
    `ShellCommandBackendConfig`, `ToolsConfig`, `ToolsConfigParams`,
    `UnifiedExecShellMode`, and `ZshForkConfig` from `codex_tools`.
    
    ## Verification
    
    - Ran `cargo test -p codex-core`.
    - The package run is currently red in five unrelated config tests in
    `core/src/config/config_tests.rs` (`approvals_reviewer_*` and
    `smart_approvals_alias_*`), while the tool/spec and shell tests touched
    by this import cleanup passed.
  • Extract tool-suggest wire helpers into codex-tools (#16499)
    ## Why
    
    This is another straight-refactor step in the `codex-tools` migration.
    
    `core/src/tools/handlers/tool_suggest.rs` still owned request/response
    payload structs, elicitation metadata shaping, and connector-completion
    predicates that do not depend on `codex-core` session/runtime internals.
    Per the `AGENTS.md` guidance to keep shrinking `codex-core`, this moves
    that pure wire-format logic into `codex-rs/tools` so the core handler
    keeps only session orchestration, plugin/config refresh, and MCP cache
    updates.
    
    ## What changed
    
    - Added `codex-rs/tools/src/tool_suggest.rs` and exported its API from
    `codex-rs/tools/src/lib.rs`.
    - Moved `ToolSuggestArgs`, `ToolSuggestResult`, `ToolSuggestMeta`,
    `build_tool_suggestion_elicitation_request()`,
    `all_suggested_connectors_picked_up()`, and
    `verified_connector_suggestion_completed()` into `codex-tools`.
    - Rewired `core/src/tools/handlers/tool_suggest.rs` to consume those
    exports directly.
    - Ported the existing pure helper tests from
    `core/src/tools/handlers/tool_suggest_tests.rs` to
    `tools/src/tool_suggest_tests.rs` without adding new behavior coverage.
    
    ## Validation
    
    ```shell
    cargo test -p codex-tools
    cargo test -p codex-core tools::handlers::tool_suggest::tests
    just argument-comment-lint
    ```
  • fix: guard guardian_command_source_tool_name with cfg(unix) (#16498)
    This currently contributing to `rust-ci-full.yml` being red on `main`
    for windows lint builds due to the cargo/bazel coverage gap that I'm
    working on. Hopefully this gets us back on track.
  • Extract tool-search output helpers into codex-tools (#16497)
    ## Why
    
    This is the next straight-refactor step in the `codex-tools` migration
    that follows #16493.
    
    `codex-rs/core` still owned a chunk of pure tool-discovery metadata and
    response shaping even though the corresponding `tool_search` /
    `tool_suggest` specs already live in `codex-rs/tools`. Per the guidance
    in `AGENTS.md`, this moves that crate-agnostic logic out of `codex-core`
    so the handler crate keeps only the BM25 ranking/orchestration and
    runtime glue.
    
    ## What changed
    
    - Moved the canonical `tool_search` / `tool_suggest` tool names and the
    `tool_search` default limit into `codex-rs/tools/src/tool_discovery.rs`.
    - Added `ToolSearchResultSource` and
    `collect_tool_search_output_tools()` in `codex-tools` so namespace
    grouping and deferred Responses API tool serialization happen outside
    `codex-core`.
    - Rewired `ToolSearchHandler`, `ToolSuggestHandler`, and
    `core/src/tools/spec.rs` to consume those exports directly from
    `codex-tools`.
    - Ported the existing `tool_search` serializer tests from
    `core/src/tools/handlers/tool_search_tests.rs` to
    `tools/src/tool_discovery_tests.rs` without adding new behavior
    coverage.
    
    ## Validation
    
    ```shell
    cargo test -p codex-tools
    cargo test -p codex-core tools::spec::tests
    just argument-comment-lint
    ```
  • Extract built-in tool spec constructors into codex-tools (#16493)
    ## Why
    
    `core/src/tools/spec.rs` still had a few built-in tool specs assembled
    inline even though those definitions are pure metadata and already live
    conceptually in `codex-tools`. Keeping that construction in `codex-core`
    makes `spec.rs` do more than registry orchestration and slows the
    migration toward a right-sized `codex-tools` crate.
    
    This continues the extraction stack from #16379, #16471, #16477, #16481,
    and #16482.
    
    ## What Changed
    
    - added `create_local_shell_tool()`, `create_web_search_tool(...)`, and
    `create_image_generation_tool(...)` to `codex-rs/tools/src/tool_spec.rs`
    - exported those helpers from `codex-rs/tools/src/lib.rs`
    - switched `codex-rs/core/src/tools/spec.rs` to call those helpers
    instead of constructing `ToolSpec::LocalShell`, `ToolSpec::WebSearch`,
    and `ToolSpec::ImageGeneration` inline
    - removed the remaining core-local web-search content-type constant and
    made the affected spec test assert the literal expected values directly
    
    This is intended to be a straight refactor: tool behavior and wire shape
    should not change.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • Remove client_common tool re-exports (#16482)
    ## Why
    
    `codex-rs/core/src/client_common.rs` still had a `tools` re-export
    module that forwarded `codex_tools` types back into `codex-core`. After
    the earlier extraction work in #16379, #16471, #16477, and #16481, that
    extra layer no longer adds value.
    
    Removing it keeps dependencies explicit: the `codex-core` modules that
    actually use `ToolSpec` and related types now depend on `codex_tools`
    directly instead of reaching through `client_common`.
    
    ## What Changed
    
    - removed the `client_common::tools` re-export module from
    `core/src/client_common.rs`
    - updated the remaining `codex-core` consumers to import `codex_tools`
    directly
    - adjusted the affected test code to reference
    `codex_tools::ResponsesApiTool` directly as well
    
    This is a mechanical cleanup only. It does not change tool behavior or
    runtime logic.
    
    ## Testing
    
    - `cargo test -p codex-core client_common::tests`
    - `cargo test -p codex-core tools::router::tests`
    - `cargo test -p codex-core tools::context::tests`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract MCP into codex-mcp crate (#15919)
    - Split MCP runtime/server code out of `codex-core` into the new
    `codex-mcp` crate. New/moved public structs/types include `McpConfig`,
    `McpConnectionManager`, `ToolInfo`, `ToolPluginProvenance`,
    `CodexAppsToolsCacheKey`, and the `McpManager` API
    (`codex_mcp::mcp::McpManager` plus the `codex_core::mcp::McpManager`
    wrapper/shim). New/moved functions include `with_codex_apps_mcp`,
    `configured_mcp_servers`, `effective_mcp_servers`,
    `collect_mcp_snapshot`, `collect_mcp_snapshot_from_manager`,
    `qualified_mcp_tool_name_prefix`, and the MCP auth/skill-dependency
    helpers. Why: this creates a focused MCP crate boundary and shrinks
    `codex-core` without forcing every consumer to migrate in the same PR.
    
    - Move MCP server config schema and persistence into `codex-config`.
    New/moved structs/enums include `AppToolApproval`,
    `McpServerToolConfig`, `McpServerConfig`, `RawMcpServerConfig`,
    `McpServerTransportConfig`, `McpServerDisabledReason`, and
    `codex_config::ConfigEditsBuilder`. New/moved functions include
    `load_global_mcp_servers` and
    `ConfigEditsBuilder::replace_mcp_servers`/`apply`. Why: MCP TOML
    parsing/editing is config ownership, and this keeps config
    validation/round-tripping (including per-tool approval overrides and
    inline bearer-token rejection) in the config crate instead of
    `codex-core`.
    
    - Rewire `codex-core`, app-server, and plugin call sites onto the new
    crates. Updated `Config::to_mcp_config(&self, plugins_manager)`,
    `codex-rs/core/src/mcp.rs`, `codex-rs/core/src/connectors.rs`,
    `codex-rs/core/src/codex.rs`,
    `CodexMessageProcessor::list_mcp_server_status_task`, and
    `utils/plugins/src/mcp_connector.rs` to build/pass the new MCP
    config/runtime types. Why: plugin-provided MCP servers still merge with
    user-configured servers, and runtime auth (`CodexAuth`) is threaded into
    `with_codex_apps_mcp` / `collect_mcp_snapshot` explicitly so `McpConfig`
    stays config-only.
  • Extract update_plan tool spec into codex-tools (#16481)
    ## Why
    
    `codex-rs/core/src/tools/handlers/plan.rs` still owned both the
    `update_plan` runtime handler and the static tool definition. The tool
    definition is pure metadata, so keeping it in `codex-core` works against
    the ongoing effort to move tool-spec code into `codex-tools` and keep
    `codex-core` focused on orchestration and execution paths.
    
    This continues the extraction work from #16379, #16471, and #16477.
    
    ## What Changed
    
    - added `codex-rs/tools/src/plan_tool.rs` with
    `create_update_plan_tool()`
    - re-exported that constructor from `codex-rs/tools/src/lib.rs`
    - updated `codex-rs/core/src/tools/spec.rs` and
    `codex-rs/core/src/tools/spec_tests.rs` to use the `codex-tools` export
    instead of a core-local static
    - removed the old `PLAN_TOOL` definition from
    `codex-rs/core/src/tools/handlers/plan.rs`; the `PlanHandler` runtime
    logic still stays in `codex-core`
    - tightened two `codex-core` aliases to `#[cfg(test)]` now that
    production code no longer needs them
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16481).
    * #16482
    * __->__ #16481
  • fix(guardian): make GuardianAssessmentEvent.action strongly typed (#16448)
    ## Description
    
    Previously the `action` field on `EventMsg::GuardianAssessment`, which
    describes what Guardian is reviewing, was typed as an arbitrary JSON
    blob. This PR cleans it up and defines a sum type representing all the
    various actions that Guardian can review.
    
    This is a breaking change (on purpose), which is fine because:
    - the Codex app / VSCE does not actually use `action` at the moment
    - the TUI code that consumes `action` is updated in this PR as well
    - rollout files that serialized old `EventMsg::GuardianAssessment` will
    just silently drop these guardian events
    - the contract is defined as unstable, so other clients have a fair
    warning :)
    
    This will make things much easier for followup Guardian work.
    
    ## Why
    
    The old guardian review payloads worked, but they pushed too much shape
    knowledge into downstream consumers. The TUI had custom JSON parsing
    logic for commands, patches, network requests, and MCP calls, and the
    app-server protocol was effectively just passing through an opaque blob.
    
    Typing this at the protocol boundary makes the contract clearer.
  • login: treat provider auth refresh_interval_ms=0 as no auto-refresh (#16480)
    ## Why
    
    Follow-up to #16288: the new dynamic provider auth token flow currently
    defaults `refresh_interval_ms` to a non-zero value and rejects `0`
    entirely.
    
    For command-backed bearer auth, `0` should mean "never auto-refresh".
    That lets callers keep using the cached token until the backend actually
    returns `401 Unauthorized`, at which point Codex can rerun the auth
    command as part of the existing retry path.
    
    ## What changed
    
    - changed `ModelProviderAuthInfo.refresh_interval_ms` to accept `0` and
    documented that value as disabling proactive refresh
    - updated the external bearer token refresher to treat
    `refresh_interval_ms = 0` as an indefinitely reusable cached token,
    while still rerunning the auth command during unauthorized recovery
    - regenerated `core/config.schema.json` so the schema minimum is `0` and
    the new behavior is described in the field docs
    - added coverage for both config deserialization and the no-auto-refresh
    plus `401` recovery behavior
    
    ## How tested
    
    - `cargo test -p codex-protocol`
    - `cargo test -p codex-login`
    - `cargo test -p codex-core test_deserialize_provider_auth_config_`
  • Extract tool discovery helpers into codex-tools (#16477)
    ## Why
    
    Follow-up to #16379 and #16471.
    
    `codex-rs/core/src/tools/spec.rs` still owned the pure discovery-shaping
    helpers that turn app metadata and discoverable tool metadata into the
    inputs used by `tool_search` and `tool_suggest`. Those helpers do not
    need `codex-core` runtime state, so keeping them in `codex-core`
    continued to blur the crate boundary this migration is trying to
    tighten.
    
    This change keeps pushing spec-only logic behind the `codex-tools` API
    so `codex-core` can focus on wiring runtime handlers to the resulting
    tool definitions.
    
    ## What Changed
    
    - Added `collect_tool_search_app_infos` and
    `collect_tool_suggest_entries` to
    `codex-rs/tools/src/tool_discovery.rs`.
    - Added a small `ToolSearchAppSource` adapter type in `codex-tools` so
    `codex-core` can pass app metadata into that shared helper logic without
    exposing `ToolInfo` across the crate boundary.
    - Re-exported the new discovery helpers from
    `codex-rs/tools/src/lib.rs`, which remains exports-only.
    - Updated `codex-rs/core/src/tools/spec.rs` to use those `codex-tools`
    helpers instead of maintaining local `tool_search_app_infos` and
    `tool_suggest_entries` functions.
    - Removed the now-redundant helper implementations from `codex-core`.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract tool spec helpers into codex-tools (#16471)
    ## Why
    
    Follow-up to #16379.
    
    `codex-rs/core/src/tools/spec.rs` and the corresponding handlers still
    owned several pure tool-definition helpers even though they do not need
    `codex-core` runtime state. Keeping that spec-only logic in `codex-core`
    keeps the crate boundary blurry and works against the guidance in
    `AGENTS.md` to keep shared tooling out of `codex-core` when possible.
    
    This change takes another step toward a dedicated `codex-tools` crate by
    moving more metadata and schema-building code behind the `codex-tools`
    API while leaving the actual tool execution paths in `codex-core`.
    
    ## What Changed
    
    - Added `codex-rs/tools/src/apply_patch_tool.rs` to own
    `ApplyPatchToolArgs`, the freeform/json `apply_patch` tool specs, and
    the moved `tool_apply_patch.lark` grammar.
    - Updated `codex-rs/tools/BUILD.bazel` so Bazel exposes the moved
    grammar file to `codex-tools`.
    - Moved the `request_user_input` availability and description helpers
    into `codex-rs/tools/src/request_user_input_tool.rs`, with the related
    unit tests moved alongside that business logic.
    - Moved `request_permissions_tool_description()` into
    `codex-rs/tools/src/local_tool.rs`.
    - Rewired `codex-rs/core/src/tools/spec.rs`,
    `codex-rs/core/src/tools/handlers/apply_patch.rs`, and
    `codex-rs/core/src/tools/handlers/request_user_input.rs` to consume the
    new `codex-tools` exports instead of local helper code.
    - Removed the now-redundant helper implementations and tests from
    `codex-core`, plus a couple of stale `client_common` re-exports that
    became unused after the move.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    - `cargo test -p codex-core tools::handlers::apply_patch::tests`
  • Extract tool config into codex-tools (#16379)
    ## Why
    
    `codex-core` already owns too much of the tool stack, and `AGENTS.md`
    explicitly pushes us to move shared code out of `codex-core` instead of
    letting it keep growing. This PR takes the next incremental step in
    moving `core/src/tools` toward `codex-rs/tools` by extracting
    low-coupling tool configuration and image-detail gating logic into
    `codex-tools`.
    
    That gives later extraction work a cleaner boundary to build on without
    trying to move the entire tools subtree in one shot.
    
    ## What changed
    
    - moved `ToolsConfig`, `ToolsConfigParams`, shell backend config, and
    unified-exec session selection from `core/src/tools/spec.rs` into
    `codex-tools`
    - moved original image-detail gating and normalization into
    `codex-tools`
    - updated `codex-core` to consume the new `codex-tools` exports and pass
    a rendered agent-type description instead of raw role config
    - kept `codex-rs/tools/src/lib.rs` exports-only, with extracted unit
    tests living in sibling `*_tests.rs` modules
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
  • fix(core) rm execute_exec_request sandbox_policy (#16422)
    ## Summary
    In #11871 we started consolidating on ExecRequest.sandbox_policy instead
    of passing in a separate policy object that theoretically could differ
    (but did not). This finishes the some parameter cleanup.
    
    This should be a simple noop, since all 3 callsites of this function
    already used a cloned object from the ExecRequest value.
    
    ## Testing
    - [x] Existing tests pass
  • Use message string in v2 assign_task (#16419)
    Fix assign task and clean everything
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Use message string in v2 send_message (#16409)
    ## Summary
    - switch MultiAgentV2 send_message to accept a single message string
    instead of items
    - keep the old assign_task item parser in place for the next branch
    - update send_message schema/spec and focused handler tests
    
    ## Verification
    - cargo test -p codex-tools
    send_message_tool_requires_message_and_uses_submission_output
    - cargo test -p codex-core multi_agent_v2_send_message
    - just fix -p codex-tools
    - just fix -p codex-core
    - just argument-comment-lint
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>