Commit Graph

205 Commits

  • fix: restore MCP startup progress messages in TUI (fixes #7827) (#7828)
    ## Problem
    
    The introduction of `notify_sandbox_state_change()` in #7112 caused a
    regression where the blocking call in `Session::new()` waits for all MCP
    servers to fully initialize before returning. This prevents the TUI
    event loop from starting, resulting in `McpStartupUpdateEvent` messages
    being emitted but never consumed or displayed. As a result, the app
    appears to hang during startup, and users do not see the expected
    "Booting MCP server: {name}" status line.
    
    Issue: [#7827](https://github.com/openai/codex/issues/7827)
    
    ## Solution
    This change moves sandbox state notification into each MCP server's
    background initialization task. The notification is sent immediately
    after the server transitions to the Ready state. This approach:
    - Avoids blocking `Session::new()`, allowing the TUI event loop to start
    promptly.
    - Ensures each MCP server receives its sandbox state before handling any
    tool calls.
    - Restores the display of "Booting MCP server" status lines during
    startup.
    
    ## Key Changes
    - Added `ManagedClient::notify_sandbox_state()` method.
    - Passed sandbox_state to `McpConnectionManager::initialize()`.
    - Sends sandbox state notification in the background task after the
    server reaches Ready status.
    - Removed blocking notify_sandbox_state_change() methods.
    - Added a chatwidget snapshot test for the "Booting MCP server" status
    line.
    
    ## Regression Details
    
    Regression was bisected to #7112, which introduced the blocking
    behavior.
    
    ---------
    
    Co-authored-by: Michael Bolin <bolinfest@gmail.com>
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • Fix misleading 'maximize' high effort description on xhigh models (#7874)
    ## Notes
    - switch misleading High reasoning effort descriptions from "Maximizes
    reasoning depth" to "Higher reasoning depth" across models with xhigh
    reasoning. Affects GPT-5.1 Codex Max and Robin
    - refresh model list fixtures and chatwidget snapshots to match new copy
    
    ## Revision
    - R2: Change 'Higher' to 'Greater'
    - R1: Initial
    
    ## Testing
    
    <img width="583" height="142" alt="image"
    src="https://github.com/user-attachments/assets/1ddd8971-7841-4cb3-b9ba-91095a7435d2"
    />
    
    <img width="838" height="142" alt="image"
    src="https://github.com/user-attachments/assets/79aaedbf-7624-4695-b822-93dea7d6a800"
    />
  • feat: robin (#7882)
    <img width="554" height="554" alt="image"
    src="https://github.com/user-attachments/assets/aa86f4c8-fb34-4b0e-8b03-3a9980dfdb08"
    />
    
    ---------
    
    Co-authored-by: Dylan Hurd <dylan.hurd@openai.com>
  • fix(stuff) (#7855)
    Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
  • Inject SKILL.md when it's explicitly mentioned. (#7763)
    1. Skills load once in core at session start; the cached outcome is
    reused across core and surfaced to TUI via SessionConfigured.
    2. TUI detects explicit skill selections, and core injects the matching
    SKILL.md content into the turn when a selected skill is present.
  • make model optional in config (#7769)
    - Make Config.model optional and centralize default-selection logic in
    ModelsManager, including a default_model helper (with
    codex-auto-balanced when available) so sessions now carry an explicit
    chosen model separate from the base config.
    - Resolve `model` once in `core` and `tui` from config. Then store the
    state of it on other structs.
    - Move refreshing models to be before resolving the default model
  • Removed experimental "command risk assessment" feature (#7799)
    This experimental feature received lukewarm reception during internal
    testing. Removing from the code base.
  • Express rate limit warning as % remaining (#7795)
    <img width="342" height="264" alt="image"
    src="https://github.com/user-attachments/assets/f1e932ff-c550-47b3-9035-0299ada4998d"
    />
    
    Earlier, the warning was expressed as consumed% whereas status was
    expressed as remaining%. This change brings the two into sync to
    minimize confusion and improve visual consistency.
  • Remove legacy ModelInfo and merge it with ModelFamily (#7748)
    This is a step towards removing the need to know `model` when
    constructing config. We firstly don't need to know `model_info` and just
    respect if the user has already set it. Next step, we don't need to know
    `model` unless the user explicitly set it in `config.toml`
  • Restore status header after stream recovery (#7660)
    ## Summary
    - restore the previous status header when a non-error event arrives
    after a stream retry
    - add a regression test to ensure the reconnect banner clears once
    streaming resumes
    
    ## Testing
    - cargo fmt -- --config imports_granularity=Item
    - cargo clippy --fix --all-features --tests --allow-dirty -p codex-tui
    - NO_COLOR=0 cargo test -p codex-tui *(fails: vt100 color assertion
    tests expect colored cells but the environment returns Default colors
    even with NO_COLOR cleared and TERM/COLORTERM set)*
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_69337f8c77508329b3ea85134d4a7ac7)
  • Enhance model picker (#7709)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • load models from disk and set a ttl and etag (#7722)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • Wire with_remote_overrides to construct model families (#7621)
    - This PR wires `with_remote_overrides` and make the
    `construct_model_families` an async function
    - Moves getting model family a level above to keep the function `sync`
    - Updates the tests to local, offline, and `sync` helper for model
    families
  • fix: taking plan type from usage endpoint instead of thru auth token (#7610)
    pull plan type from the usage endpoint, persist it in session state /
    tui state, and propagate through rate limit snapshots
  • Call models endpoint in models manager (#7616)
    - Introduce `with_remote_overrides` and update
    `refresh_available_models`
    - Put `auth_manager` instead of `auth_mode` on `models_manager`
    - Remove `ShellType` and `ReasoningLevel` to use already existing
    structs
  • execpolicy tui flow (#7543)
    ## Updating the `execpolicy` TUI flow
    
    In the TUI, when going through the command approval flow, codex will now
    ask the user if they would like to whitelist the FIRST unmatched command
    among a chain of commands.
    
    For example, let's say the agent wants to run `apple | pear` with an
    empty `execpolicy`
    
    Neither apple nor pear will match to an `execpolicy` rule. Thus, when
    prompting the user, codex tui will ask the user if they would like to
    whitelist `apple`.
    
    If the agent wants to run `apple | pear` again, they would be prompted
    again because pear is still unknown. when prompted, the user will now be
    asked if they'd like to whitelist `pear`.
    
    Here's a demo video of this flow:
    
    
    https://github.com/user-attachments/assets/fd160717-f6cb-46b0-9f4a-f0a974d4e710
    
    This PR also removed the `allow for this session` option from the TUI.
  • Refactor execpolicy fallback evaluation (#7544)
    ## Refactor of the `execpolicy` crate
    
    To illustrate why we need this refactor, consider an agent attempting to
    run `apple | rm -rf ./`. Suppose `apple` is allowed by `execpolicy`.
    Before this PR, `execpolicy` would consider `apple` and `pear` and only
    render one rule match: `Allow`. We would skip any heuristics checks on
    `rm -rf ./` and immediately approve `apple | rm -rf ./` to run.
    
    To fix this, we now thread a `fallback` evaluation function into
    `execpolicy` that runs when no `execpolicy` rules match a given command.
    In our example, we would run `fallback` on `rm -rf ./` and prevent
    `apple | rm -rf ./` from being run without approval.
  • whitelist command prefix integration in core and tui (#7033)
    this PR enables TUI to approve commands and add their prefixes to an
    allowlist:
    <img width="708" height="605" alt="Screenshot 2025-11-21 at 4 18 07 PM"
    src="https://github.com/user-attachments/assets/56a19893-4553-4770-a881-becf79eeda32"
    />
    
    note: we only show the option to whitelist the command when 
    1) command is not multi-part (e.g `git add -A && git commit -m 'hello
    world'`)
    2) command is not already matched by an existing rule
  • Migrate codex max (#7566)
    - make codex max the default
    - fix: we were doing some async work in sync function which caused tui
    to panic
  • Migrate tui to use models manager (#7555)
    - This PR treats the `ModelsManager` like `AuthManager` and propagate it
    into the tui, replacing the `builtin_model_presets`
    - We are also decreasing the visibility of `builtin_model_presets`
    
    based on https://github.com/openai/codex/pull/7552
  • feat: Support listing and selecting skills via $ or /skills (#7506)
    List/Select skills with $-mention or /skills
  • Migrate model preset (#7542)
    - Introduce `openai_models` in `/core`
    - Move `PRESETS` under it
    - Move `ModelPreset`, `ModelUpgrade`, `ReasoningEffortPreset`,
    `ReasoningEffortPreset`, and `ReasoningEffortPreset` to `protocol`
    - Introduce `Op::ListModels` and `EventMsg::AvailableModels`
    
    Next steps:
    - migrate `app-server` and `tui` to use the introduced Operation
  • add slash resume (#7302)
    `codex resume` isn't that discoverable. Adding it to the slash commands
    can help
  • feat: codex tool tips (#7440)
    <img width="551" height="316" alt="Screenshot 2025-12-01 at 12 22 26"
    src="https://github.com/user-attachments/assets/6ca3deff-8ef8-4f74-a8e1-e5ea13fd6740"
    />
  • persisting credits if new snapshot does not contain credit info (#7490)
    in response to incoming changes to responses headers where the header
    may sometimes not contain credits info (no longer forcing a credit
    check)
  • Show token used when context window is unknown (#7497)
    - Show context window usage in tokens instead of percentage when the
    window length is unknown.
  • correctly recognize WorkspaceWrite policy on /approvals (#7301)
    the `/approvals` popup fails to recognize that the CLI is in
    WorkspaceWrite mode if that policy has extra bits, like `writable_roots`
    etc.
    
    This change matches the policy, ignoring additional config aspects.
  • chore: dedup unified exec "waited" rendering (#7256)
    From
    <img width="477" height="283" alt="Screenshot 2025-11-24 at 18 02 25"
    src="https://github.com/user-attachments/assets/724d1d68-c994-417e-9859-ada8eb173b4c"
    />
    To
    <img width="444" height="174" alt="Screenshot 2025-11-24 at 18 02 40"
    src="https://github.com/user-attachments/assets/40f91247-6d55-4428-84d1-f39c912ac2e7"
    />
  • support MCP elicitations (#6947)
    No support for request schema yet, but we'll at least show the message
    and allow accept/decline.
    
    <img width="823" height="551" alt="Screenshot 2025-11-21 at 2 44 05 PM"
    src="https://github.com/user-attachments/assets/6fbb892d-ca12-4765-921e-9ac4b217534d"
    />
  • [app-server] update doc with codex error info (#6941)
    Document new codex error info. Also fixed the name from
    `codex_error_code` to `codex_error_info`.
  • [app-server & core] introduce new codex error code and v2 app-server error events (#6938)
    This PR does two things:
    1. populate a new `codex_error_code` protocol in error events sent from
    core to client;
    2. old v1 core events `codex/event/stream_error` and `codex/event/error`
    will now both become `error`. We also show codex error code for
    turncompleted -> error status.
    
    new events in app server test:
    ```
    < {
    <   "method": "codex/event/stream_error",
    <   "params": {
    <     "conversationId": "019aa34c-0c14-70e0-9706-98520a760d67",
    <     "id": "0",
    <     "msg": {
    <       "codex_error_code": {
    <         "response_stream_disconnected": {
    <           "http_status_code": 401
    <         }
    <       },
    <       "message": "Reconnecting... 2/5",
    <       "type": "stream_error"
    <     }
    <   }
    < }
    
     {
    <   "method": "error",
    <   "params": {
    <     "error": {
    <       "codexErrorCode": {
    <         "responseStreamDisconnected": {
    <           "httpStatusCode": 401
    <         }
    <       },
    <       "message": "Reconnecting... 2/5"
    <     }
    <   }
    < }
    
    < {
    <   "method": "turn/completed",
    <   "params": {
    <     "turn": {
    <       "error": {
    <         "codexErrorCode": {
    <           "responseTooManyFailedAttempts": {
    <             "httpStatusCode": 401
    <           }
    <         },
    <         "message": "exceeded retry limit, last status: 401 Unauthorized, request id: 9a1b495a1a97ed3e-SJC"
    <       },
    <       "id": "0",
    <       "items": [],
    <       "status": "failed"
    <     }
    <   }
    < }
    ```
  • Added feature switch to disable animations in TUI (#6870)
    This PR adds support for a new feature flag `tui.animations`. By
    default, the TUI uses animations in its welcome screen, "working"
    spinners, and "shimmer" effects. This animations can interfere with
    screen readers, so it's good to provide a way to disable them.
    
    This change is inspired by [a
    PR](https://github.com/openai/codex/pull/4014) contributed by @Orinks.
    That PR has faltered a bit, but I think the core idea is sound. This
    version incorporates feedback from @aibrahim-oai. In particular:
    1. It uses a feature flag (`tui.animations`) rather than the unqualified
    CLI key `no-animations`. Feature flags are the preferred way to expose
    boolean switches. They are also exposed via CLI command switches.
    2. It includes more complete documentation.
    3. It disables a few animations that the other PR omitted.
  • [app-server] feat: v2 apply_patch approval flow (#6760)
    This PR adds the API V2 version of the apply_patch approval flow, which
    centers around `ThreadItem::FileChange`.
    
    This PR wires the new RPC (`item/fileChange/requestApproval`, V2 only)
    and related events (`item/started`, `item/completed` for
    `ThreadItem::FileChange`, which are emitted in both V1 and V2) through
    the app-server
    protocol. The new approval RPC is only sent when the user initiates a
    turn with the new `turn/start` API so we don't break backwards
    compatibility with VSCE.
    
    Similar to https://github.com/openai/codex/pull/6758, the approach I
    took was to make as few changes to the Codex core as possible,
    leveraging existing `EventMsg` core events, and translating those in
    app-server. I did have to add a few additional fields to
    `EventMsg::PatchApplyBegin` and `EventMsg::PatchApplyEnd`, but those
    were fairly lightweight.
    
    However, the `EventMsg`s emitted by core are the following:
    ```
    1) Auto-approved (no request for approval)

    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    
    2) Approved by user
    - EventMsg::ApplyPatchApprovalRequest
    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    
    3) Declined by user
    - EventMsg::ApplyPatchApprovalRequest
    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    ```
    
    For a request triggering an approval, this would result in:
    ```
    item/fileChange/requestApproval
    item/started
    item/completed
    ```
    
    which is different from the `ThreadItem::CommandExecution` flow
    introduced in https://github.com/openai/codex/pull/6758, which does the
    below and is preferable:
    ```
    item/started
    item/commandExecution/requestApproval
    item/completed
    ```
    
    To fix this, we leverage `TurnSummaryStore` on codex_message_processor
    to store a little bit of state, allowing us to fire `item/started` and
    `item/fileChange/requestApproval` whenever we receive the underlying
    `EventMsg::ApplyPatchApprovalRequest`, and no-oping when we receive the
    `EventMsg::PatchApplyBegin` later.
    
    This is much less invasive than modifying the order of EventMsg within
    core (I tried).
    
    The resulting payloads:
    ```
    {
      "method": "item/started",
      "params": {
        "item": {
          "changes": [
            {
              "diff": "Hello from Codex!\n",
              "kind": "add",
              "path": "/Users/owen/repos/codex/codex-rs/APPROVAL_DEMO.txt"
            }
          ],
          "id": "call_Nxnwj7B3YXigfV6Mwh03d686",
          "status": "inProgress",
          "type": "fileChange"
        }
      }
    }
    ```
    
    ```
    {
      "id": 0,
      "method": "item/fileChange/requestApproval",
      "params": {
        "grantRoot": null,
        "itemId": "call_Nxnwj7B3YXigfV6Mwh03d686",
        "reason": null,
        "threadId": "019a9e11-8295-7883-a283-779e06502c6f",
        "turnId": "1"
      }
    }
    ```
    
    ```
    {
      "id": 0,
      "result": {
        "decision": "accept"
      }
    }
    ```
    
    ```
    {
      "method": "item/completed",
      "params": {
        "item": {
          "changes": [
            {
              "diff": "Hello from Codex!\n",
              "kind": "add",
              "path": "/Users/owen/repos/codex/codex-rs/APPROVAL_DEMO.txt"
            }
          ],
          "id": "call_Nxnwj7B3YXigfV6Mwh03d686",
          "status": "completed",
          "type": "fileChange"
        }
      }
    }
    ```
  • Revert "[core] add optional status_code to error events (#6865)" (#6955)
    This reverts commit c2ec477d93.
    
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • execpolicy2 core integration (#6641)
    This PR threads execpolicy2 into codex-core.
    
    activated via feature flag: exec_policy (on by default)
    
    reads and parses all .codexpolicy files in `codex_home/codex`
    
    refactored tool runtime API to integrate execpolicy logic
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • fix(context left after review): review footer context after /review (#5610)
    ## Summary
    - show live review token usage while `/review` runs and restore the main
    session indicator afterward
      - add regression coverage for the footer behavior
    
    ## Testing
      - just fmt
      - cargo test -p codex-tui
    
    Fixes #5604
    
    ---------
    
    Signed-off-by: Fahad <fahad@2doapp.com>
  • [core] add optional status_code to error events (#6865)
    We want to better uncover error status code for clients. Add an optional
    status_code to error events (thread error, error, stream error) so app
    server could uncover the status code from the client side later.
    
    in event log:
    ```
    < {
    <   "method": "codex/event/stream_error",
    <   "params": {
    <     "conversationId": "019a9a32-f576-7292-9711-8e57e8063536",
    <     "id": "0",
    <     "msg": {
    <       "message": "Reconnecting... 5/5",
    <       "status_code": 401,
    <       "type": "stream_error"
    <     }
    <   }
    < }
    < {
    <   "method": "codex/event/error",
    <   "params": {
    <     "conversationId": "019a9a32-f576-7292-9711-8e57e8063536",
    <     "id": "0",
    <     "msg": {
    <       "message": "exceeded retry limit, last status: 401 Unauthorized, request id: 9a0cb03a485067f7-SJC",
    <       "status_code": 401,
    <       "type": "error"
    <     }
    <   }
    < }
    ```
  • storing credits (#6858)
    Expand the rate-limit cache/TUI: store credit snapshots alongside
    primary and secondary windows, render “Credits” when the backend reports
    they exist (unlimited vs rounded integer balances)
  • feat: arcticfox in the wild (#6906)
    <img width="485" height="600" alt="image"
    src="https://github.com/user-attachments/assets/4341740d-dd58-4a3e-b69a-33a3be0606c5"
    />
    
    ---------
    
    Co-authored-by: jif-oai <jif@openai.com>
  • fix: typos in model picker (#6859)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • feat: tweak windows sandbox strings (#6875)
    New strings:
    1. Approval mode picker just says "Select Approval Mode"
    1. Updated "Auto" to "Agent"
    1. When you select "Agent", you get "Agent mode on Windows uses an
    experimental sandbox to limit network and filesystem access. [Learn
    more]"
    1. Updated world-writable warning to "The Windows sandbox cannot protect
    writes to folders that are writable by Everyone. Consider removing write
    access for Everyone from the following folders: {folders}"
    
    ---------
    
    Co-authored-by: iceweasel-oai <iceweasel@openai.com>
  • fix: add more fields to ThreadStartResponse and ThreadResumeResponse (#6847)
    This adds the following fields to `ThreadStartResponse` and
    `ThreadResumeResponse`:
    
    ```rust
        pub model: String,
        pub model_provider: String,
        pub cwd: PathBuf,
        pub approval_policy: AskForApproval,
        pub sandbox: SandboxPolicy,
        pub reasoning_effort: Option<ReasoningEffort>,
    ```
    
    This is important because these fields are optional in
    `ThreadStartParams` and `ThreadResumeParams`, so the caller needs to be
    able to determine what values were ultimately used to start/resume the
    conversation. (Though note that any of these could be changed later
    between turns in the conversation.)
    
    Though to get this information reliably, it must be read from the
    internal `SessionConfiguredEvent` that is created in response to the
    start of a conversation. Because `SessionConfiguredEvent` (as defined in
    `codex-rs/protocol/src/protocol.rs`) did not have all of these fields, a
    number of them had to be added as part of this PR.
    
    Because `SessionConfiguredEvent` is referenced in many tests, test
    instances of `SessionConfiguredEvent` had to be updated, as well, which
    is why this PR touches so many files.