Commit Graph

2890 Commits

  • Introduce collaboration modes (#9340)
    - Merge `model` and `reasoning_effort` under collaboration modes.
    - Add additional instructions for custom collaboration mode
    - Default to Custom to not change behavior
  • feat: show forked from session id in /status (#9330)
    Summary:
    - Add forked_from to SessionMeta/SessionConfiguredEvent and persist it
    for forked sessions.
    - Surface forked_from in /status for tui + tui2 and add snapshots.
  • feat(app-server, core): return threads by created_at or updated_at (#9247)
    Add support for returning threads by either `created_at` OR `updated_at`
    descending. Previously core always returned threads ordered by
    `created_at`.
    
    This PR:
    - updates core to be able to list threads by `updated_at` OR
    `created_at` descending based on what the caller wants
    - also update `thread/list` in app-server to expose this (default to
    `created_at` if not specified)
    
    All existing codepaths (app-server, TUI) still default to `created_at`,
    so no behavior change is expected with this PR.
    
    **Implementation**
    To sort by `updated_at` is a bit nontrivial (whereas `created_at` is
    easy due to the way we structure the folders and filenames on disk,
    which are all based on `created_at`).
    
    The most naive way to do this without introducing a cache file or sqlite
    DB (which we have to implement/maintain) is to scan files in reverse
    `created_at` order on disk, and look at the file's mtime (last modified
    timestamp according to the filesystem) until we reach `MAX_SCAN_FILES`
    (currently set to 10,000). Then, we can return the most recent N
    threads.
    
    Based on some quick and dirty benchmarking on my machine with ~1000
    rollout files, calling `thread/list` with limit 50, the `updated_at`
    path is slower as expected due to all the I/O:
    - updated-at: average 103.10 ms
    - created-at: average 41.10 ms
    
    Those absolute numbers aren't a big deal IMO, but we can certainly
    optimize this in a followup if needed by introducing more state stored
    on disk.
    
    **Caveat**
    There's also a limitation in that any files older than `MAX_SCAN_FILES`
    will be excluded, which means if a user continues a REALLY old thread,
    it's possible to not be included. In practice that should not be too big
    of an issue.
    
    If a user makes...
    - 1000 rollouts/day → threads older than 10 days won't show up
    - 100 rollouts/day → ~100 days
    
    If this becomes a problem for some reason, even more motivation to
    implement an updated_at cache.
  • feat: /fork the current session instead of opening session picker (#9385)
    Implemented /fork to fork the current session directly (no picker),
    handling it via a new ForkCurrentSession app event in both tui and tui2.
    Updated slash command descriptions/tooltips and adjusted the fork tests
    accordingly. Removed the unused in-session fork picker event.
  • chore: upgrade to Rust 1.92.0 (#8860)
    **Summary**
    - Upgrade Rust toolchain used by CI to 1.92.0.
    - Address new clippy `derivable_impls` warnings by deriving `Default`
    for enums across protocol, core, backend openapi models, and
    windows-sandbox setup.
    - Tidy up related test/config behavior (originator header handling, env
    override cleanup) and remove a now-unused assignment in TUI/TUI2 render
    layout.
    
    **Testing**
    - `just fmt`
    - `just fix -p codex-tui`
    - `just fix -p codex-tui2`
    - `just fix -p codex-windows-sandbox`
    - `cargo test -p codex-tui`
    - `cargo test -p codex-tui2`
    - `cargo test -p codex-windows-sandbox`
    - `cargo test -p codex-core --test all`
    - `cargo test -p codex-app-server --test all`
    - `cargo test -p codex-mcp-server --test all`
    - `cargo test --all-features`
  • Turn-state sticky routing per turn (#9332)
    - capture the header from SSE/WS handshakes, store it per
    ModelClientSession using `Oncelock`, echo it on turn-scoped requests,
    and add SSE+WS integration tests for within-turn persistence +
    cross-turn reset.
    
    - keep `x-codex-turn-state` sticky within a user turn to maintain
    routing continuity for retries/tool follow-ups.
  • add codex cloud list (#9324)
    for listing cloud tasks.
  • Made codex exec resume --last consistent with codex resume --last (#9352)
    PR #9245 made `codex resume --last` honor cwd, but I forgot to make the
    same change for `codex exec resume --last`. This PR fixes the
    inconsistency.
    
    This addresses #8700
  • chore: close pipe on non-pty processes (#9369)
    Closing the STDIN of piped process when starting them to avoid commands
    like `rg` to wait for content on STDIN and hangs for ever
  • feat: run user commands under user snapshot (#9357)
    The initial goal is for user snapshots to have access to aliases etc
  • feat: propagate approval request of unsubscribed threads (#9232)
    A thread can now be spawned by another thread. In order to process the
    approval requests of such sub-threads, we need to detect those event and
    show them in the TUI.
    
    This is a temporary solution while the UX is being figured out. This PR
    should be reverted once done
  • rename model turn to sampling request (#9336)
    We have two type of turns now: model and user turns. It's always
    confusing to refer to either. Model turn is basically a sampling
    request.
  • fix(tui): only show 'Worked for' separator when actual work was performed (#8958)
    Fixes #7919.
    
    This PR addresses a TUI display bug where the "Worked for" separator
    would appear prematurely during the planning stage.
    
    **Changes:**
    - Added `had_work_activity` flag to `ChatWidget` to track if actual work
    (exec commands, MCP tool calls, patches) was performed in the current
    turn.
    - Updated `handle_streaming_delta` to only display the
    `FinalMessageSeparator` if both `needs_final_message_separator` AND
    `had_work_activity` are true.
    - Updated `handle_exec_end_now`, `handle_patch_apply_end_now`, and
    `handle_mcp_end_now` to set `had_work_activity = true`.
    
    **Verification:**
    - Ran `cargo test -p codex-tui` to ensure no regressions.
    - Manual verification confirms the separator now only appears after
    actual work is completed.
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • chore(windows) Enable Powershell UTF8 feature (#9195)
    ## Summary
    We've received a lot of positive feedback about this feature, so we're
    going to enable it by default.
  • Add text element metadata to protocol, app server, and core (#9331)
    The second part of breaking up PR
    https://github.com/openai/codex/pull/9116
    
    Summary:
    
    - Add `TextElement` / `ByteRange` to protocol user inputs and user
    message events with defaults.
    - Thread `text_elements` through app-server v1/v2 request handling and
    history rebuild.
    - Preserve UI metadata only in user input/events (not `ContentItem`)
    while keeping local image attachments in user events for rehydration.
    
    Details:
    
    - Protocol: `UserInput::Text` carries `text_elements`;
    `UserMessageEvent` carries `text_elements` + `local_images`.
    Serialization includes empty vectors for backward compatibility.
    - app-server-protocol: v1 defines `V1TextElement` / `V1ByteRange` in
    camelCase with conversions; v2 uses its own camelCase wrapper.
    - app-server: v1/v2 input mapping includes `text_elements`; thread
    history rebuilds include them.
    - Core: user event emission preserves UI metadata while model history
    stays clean; history replay round-trips the metadata.
  • fix: send non-null content on elicitation Accept (#9196)
    ## Summary
    
    - When a user accepts an MCP elicitation request, send `content:
    Some(json!({}))` instead of `None`
    - MCP servers that use elicitation expect content to be present when
    action is Accept
    - This matches the expected behavior shown in tests at
    `exec-server/tests/common/lib.rs:171`
    
    ## Root Cause
    
    In `codex-rs/core/src/codex.rs`, the `resolve_elicitation` function
    always sent `content: None`:
    
    ```rust
    let response = ElicitationResponse {
        action,
        content: None,  // Always None, even for Accept
    };
    ```
    
    ## Fix
    
    Send an empty object when accepting:
    
    ```rust
    let content = match action {
        ElicitationAction::Accept => Some(serde_json::json!({})),
        ElicitationAction::Decline | ElicitationAction::Cancel => None,
    };
    ```
    
    ## Test plan
    
    - [x] Code compiles with `cargo check -p codex-core`
    - [x] Formatted with `just fmt`
    - [ ] Integration test `accept_elicitation_for_prompt_rule` (requires
    MCP server binary)
    
    Fixes #9053
  • Revert empty paste image handling (#9318)
    Revert #9049 behavior so empty paste events no longer trigger a
    clipboard image read.
  • [search] allow explicitly disabling web search (#9249)
    moving `web_search` rollout serverside, so need a way to explicitly
    disable search + signal eligibility from the client.
    
    - Add `x‑oai‑web‑search‑eligible` header that signifies whether the
    request can have web search.
    - Only attach the `web_search` tool when the resolved `WebSearchMode` is
    `Live` or `Cached`.
  • Support SKILL.toml file. (#9125)
    We’re introducing a new SKILL.toml to hold skill metadata so Codex can
    deliver a richer Skills experience.
    
    Initial focus is the interface block:
    ```
    [interface]
    display_name = "Optional user-facing name"
    short_description = "Optional user-facing description"
    icon_small = "./assets/small-400px.png"
    icon_large = "./assets/large-logo.svg"
    brand_color = "#3B82F6"
    default_prompt = "Optional surrounding prompt to use the skill with"
    ```
    
    All fields are exposed via the app server API.
    display_name and short_description are consumed by the TUI.
  • Revert recent styling change for input prompt placeholder text (#9307)
    A recent change in commit ccba737d26 modified the styling of the
    placeholder text (e.g. "Implement {feature}") in the input box of the
    CLI, changing it from non-italic to italic. I think this was likely
    unintentional. It results in a bad display appearance on some terminal
    emulators, and several users have complained about it.
    
    This change switches back to non-italic styling, restoring the older
    behavior.
    
    It addresses #9262
  • nit: clean unified exec background processes (#9304)
    To fix the occurences where the End event is received after the listener
    stopped listenning
  • revert: remove pre-Landlock bind mounts apply (#9300)
    **Description**
    
    This removes the pre‑Landlock read‑only bind‑mount step from the Linux
    sandbox so filesystem restrictions rely solely on Landlock again.
    `mounts.rs` is kept in place but left unused. The linux‑sandbox README
    is updated to match the new behavior and manual test expectations.
  • fix(exec): improve stdin prompt decoding (#9151)
    Fixes #8733.
    
    - Read prompt from stdin as raw bytes and decode more helpfully.
    - Strip UTF-8 BOM; decode UTF-16LE/UTF-16BE when a BOM is present.
    - For other non-UTF8 input, fail with an actionable message (offset +
    iconv hint).
    
    Tests: `cargo test -p codex-exec`.
  • Propagate MCP disabled reason (#9207)
    Indicate why MCP servers are disabled when they are disabled by
    requirements:
    
    ```
    ➜  codex git:(main) ✗ just codex mcp list
    cargo run --bin codex -- "$@"
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
         Running `target/debug/codex mcp list`
    Name         Command          Args  Env  Cwd  Status                                                                  Auth
    docs         docs-mcp         -     -    -    disabled: requirements (MDM com.openai.codex:requirements_toml_base64)  Unsupported
    hello_world  hello-world-mcp  -     -    -    disabled: requirements (MDM com.openai.codex:requirements_toml_base64)  Unsupported
    
    ➜  codex git:(main) ✗ just c
    cargo run --bin codex -- "$@"
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.90s
         Running `target/debug/codex`
    ╭─────────────────────────────────────────────╮
    │ >_ OpenAI Codex (v0.0.0)                    │
    │                                             │
    │ model:     gpt-5.2 xhigh   /model to change │
    │ directory: ~/code/codex/codex-rs            │
    ╰─────────────────────────────────────────────╯
    
    /mcp
    
    🔌  MCP Tools
    
      • No MCP tools available.
    
      • docs (disabled)
        • Reason: requirements (MDM com.openai.codex:requirements_toml_base64)
    
      • hello_world (disabled)
        • Reason: requirements (MDM com.openai.codex:requirements_toml_base64)
    ```
  • Changed codex resume --last to honor the current cwd (#9245)
    This PR changes `codex resume --last` to work consistently with `codex
    resume`. Namely, it filters based on the cwd when selecting the last
    session. It also supports the `--all` modifier as an override.
    
    This addresses #8700
  • feat: add agent roles to collab tools (#9275)
    Add `agent_type` parameter to the collab tool `spawn_agent` that
    contains a preset to apply on the config when spawning this agent
  • fix: fallback to Landlock-only when user namespaces unavailable and set PR_SET_NO_NEW_PRIVS early (#9250)
    fixes https://github.com/openai/codex/issues/9236
    
    ### Motivation
    - Prevent sandbox setup from failing when unprivileged user namespaces
    are denied so Landlock-only protections can still be applied.
    - Ensure `PR_SET_NO_NEW_PRIVS` is set before installing seccomp and
    Landlock restrictions to avoid kernel `EPERM`/`LandlockRestrict`
    ordering issues.
    
    ### Description
    - Add `is_permission_denied` helper that detects `EPERM` /
    `PermissionDenied` from `CodexErr` to drive fallback logic.
    - In `apply_read_only_mounts` skip read-only bind-mount setup and return
    `Ok(())` when `unshare_user_and_mount_namespaces()` fails with
    permission-denied so Landlock rules can still be installed.
    - Add `set_no_new_privs()` and call it from
    `apply_sandbox_policy_to_current_thread` before installing seccomp
    filters and Landlock rules when disk or network access is restricted.
  • Add migration_markdown in model_info (#9219)
    Next step would be to clean Model Upgrade in model presets
    
    ---------
    
    Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
    Co-authored-by: aibrahim-oai <219906144+aibrahim-oai@users.noreply.github.com>
  • Add text element metadata to types (#9235)
    Initial type tweaking PR to make the diff of
    https://github.com/openai/codex/pull/9116 smaller
    
    This should not change any behavior, just adds some fields to types
  • fix: increase timeout for release builds from 30 to 60 minutes (#9242)
    Windows builds have been tripping the 30 minute timeout. For sure, we
    need to improve this, but as a quick fix, let's just increase the
    timeout.
    
    Perhaps we should switch to `lto = "thin"` for release builds, at least
    for Windows:
    
    
    https://github.com/openai/codex/blob/3728db11b87cb8490bcf6bf2cdf0e13dcfb0c28b/codex-rs/Cargo.toml#L288
    
    See https://doc.rust-lang.org/cargo/reference/profiles.html#lto for
    details.
  • fix: eliminate unnecessary clone() for each SSE event (#9238)
    Given how many SSE events we get, seems worth fixing.
  • fix: correct linux sandbox uid/gid mapping after unshare (#9234)
    fixes https://github.com/openai/codex/issues/9233
    ## Summary
    - capture effective uid/gid before unshare for user namespace maps
    - pass captured ids into uid/gid map writer
    
    ## Testing
    - just fmt
    - just fix -p codex-linux-sandbox
    - cargo test -p codex-linux-sandbox
  • upgrade runners in rust-ci.yml to use the larger runners (#9106)
    Upgrades runners in rust-ci.yaml to larger runners
    
    ubuntu-24.04 (x64 and arm64) -> custom 16 core ubuntu 24.04 runners
    macos-14 -> mac0s-15-xlarge
    [TODO] windows (x64 and arm64) -> custom 16 core windows runners
  • add WebSearchMode enum (#9216)
    ### What
    Add `WebSearchMode` enum (disabled, cached live, defaults to cached) to
    config + V2 protocol. This enum takes precedence over legacy flags:
    `web_search_cached`, `web_search_request`, and `tools.web_search`.
    
    Keep `--search` as live.
    
    ### Tests
    Added tests
  • fix(tui): disable double-press quit shortcut (#9220)
    Disables the default Ctrl+C/Ctrl+D double-press quit UX (keeps the code
    path behind a const) while we rethink the quit/interrupt flow.
    
    Tests:
    - just fmt
    - cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs
    -p codex-tui
    - cargo test -p codex-tui --lib
  • fix(tui2): align Steer submit keys (#9218)
    - Remove legacy Ctrl+K queuing in tui2; Tab is the queue key.
    - Make Enter queue when Steer is disabled and submit immediately when
    Steer is enabled.
    - Add Steer keybinding docs on both tui and tui2 chat composers.