Commit Graph

1727 Commits

  • feat: shell_command tool (#6510)
    This adds support for a new variant of the shell tool behind a flag. To
    test, run `codex` with `--enable shell_command_tool`, which will
    register the tool with Codex under the name `shell_command` that accepts
    the following shape:
    
    ```python
    {
      command: str
      workdir: str | None,
      timeout_ms: int | None,
      with_escalated_permissions: bool | None,
      justification: str | None,
    }
    ```
    
    This is comparable to the existing tool registered under
    `shell`/`container.exec`. The primary difference is that it accepts
    `command` as a `str` instead of a `str[]`. The `shell_command` tool
    executes by running `execvp(["bash", "-lc", command])`, though the exact
    arguments to `execvp(3)` depend on the user's default shell.
    
    The hypothesis is that this will simplify things for the model. For
    example, on Windows, instead of generating:
    
    ```json
    {"command": ["pwsh.exe", "-NoLogo", "-Command", "ls -Name"]}
    ```
    
    The model could simply generate:
    
    ```json
    {"command": "ls -Name"}
    ```
    
    As part of this change, I extracted some logic out of `user_shell.rs` as
    `Shell::derive_exec_args()` so that it can be reused in
    `codex-rs/core/src/tools/handlers/shell.rs`. Note the original code
    generated exec arg lists like:
    
    ```javascript
    ["bash", "-lc", command]
    ["zsh", "-lc", command]
    ["pwsh.exe", "-NoProfile", "-Command", command]
    ```
    
    Using `-l` for Bash and Zsh, but then specifying `-NoProfile` for
    PowerShell seemed inconsistent to me, so I changed this in the new
    implementation while also adding a `use_login_shell: bool` option to
    make this explicit. If we decide to add a `login: bool` to
    `ShellCommandToolCallParams` like we have for unified exec:
    
    
    https://github.com/openai/codex/blob/807e2c27f0a9f2e85c50e7e6df5533f0d9b853c7/codex-rs/core/src/tools/handlers/unified_exec.rs#L33-L34
    
    Then this should make it straightforward to support.
  • feat: warning switch model on resume (#6507)
    <img width="1259" height="40" alt="Screenshot 2025-11-11 at 14 01 41"
    src="https://github.com/user-attachments/assets/48ead3d2-d89c-4d8a-a578-82d9663dbd88"
    />
  • Add unified exec escalation handling and tests (#6492)
    Similar implementation to the shell tool
  • Enable ghost_commit feature by default (#6041)
    ## Summary
    - enable the ghost_commit feature flag by default
    
    ## Testing
    - just fmt
    
    ------
    https://chatgpt.com/codex/tasks/task_i_6904ce2d0370832dbb3c2c09a90fb188
  • Colocate more of bash parsing (#6489)
    Move a few callsites that were detecting `bash -lc` into a shared
    helper.
  • Use codex-linux-sandbox in unified exec (#6480)
    Unified exec isn't working on Linux because we don't provide the correct
    arg0.
    
    The library we use for pty management doesn't allow setting arg0
    separately from executable. Use the same aliasing strategy we use for
    `apply_patch` for `codex-linux-sandbox`.
    
    Use `#[ctor]` hack to dispatch codex-linux-sandbox calls.
    
    
    Addresses https://github.com/openai/codex/issues/6450
  • Add user command event types (#6246)
    adding new user command event, logic in TUI to render user command
    events
  • Add opt-out for rate limit model nudge (#6433)
    ## Summary
    - add a `hide_rate_limit_model_nudge` notice flag plus config edit
    plumbing so the rate limit reminder preference is persisted and
    documented
    - extend the chat widget prompt with a "never show again" option, and
    wire new app events so selecting it hides future nudges immediately and
    writes the config
    - add unit coverage and refresh the snapshot for the three-option prompt
    
    ## Testing
    - `just fmt`
    - `just fix -p codex-tui`
    - `just fix -p codex-core`
    - `cargo test -p codex-tui`
    - `cargo test -p codex-core` *(fails at
    `exec::tests::kill_child_process_group_kills_grandchildren_on_timeout`:
    grandchild process still alive)*
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_6910d7f407748321b2661fc355416994)
  • Fix warning message phrasing (#6446)
    Small fix for sentence phrasing in the warning message
    
    Co-authored-by: AndrewNikolin <877163+AndrewNikolin@users.noreply.github.com>
  • fix(seatbelt): Allow reading hw.physicalcpu (#6421)
    Allow reading `hw.physicalcpu` so numpy can be imported when running in
    the sandbox.
     
    resolves #6420
  • Kill shell tool process groups on timeout (#5258)
    ## Summary
    - launch shell tool processes in their own process group so Codex owns
    the full tree
    - on timeout or ctrl-c, send SIGKILL to the process group before
    terminating the tracked child
    - document that the default shell/unified_exec timeout remains 1000 ms
    
    ## Original Bug
    Long-lived shell tool commands hang indefinitely because the timeout
    handler only terminated the direct child process; any grandchildren it
    spawned kept running and held the PTY open, preventing Codex from
    regaining control.
    
    ## Repro Original Bug
    Install next.js and run `next dev` (which is a long-running shell
    process with children). On openai:main, it will cause the agent to
    permanently get stuck here until human intervention. On this branch,
    this command will be terminated successfully after timeout_ms which will
    unblock the agent. This is a critical fix for unmonitored / lightly
    monitored agents that don't have immediate human observation to unblock
    them.
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
    Co-authored-by: Michael Bolin <bolinfest@gmail.com>
  • core: replace Cloudflare 403 HTML with friendly message (#6252)
    ### Motivation
    
    When Codex is launched from a region where Cloudflare blocks access (for
    example, Russia), the CLI currently dumps Cloudflare’s entire HTML error
    page. This isn’t actionable and makes it hard for users to understand
    what happened. We want to detect the Cloudflare block and show a
    concise, user-friendly explanation instead.
    
    ### What Changed
    
    - Added CLOUDFLARE_BLOCKED_MESSAGE and a friendly_message() helper to
    UnexpectedResponseError. Whenever we see a 403 whose body contains the
    Cloudflare block notice, we now emit a single-line message (Access
    blocked by Cloudflare…) while preserving the HTTP status and request id.
    All other responses keep the original behaviour.
    - Added two focused unit tests:
    - unexpected_status_cloudflare_html_is_simplified ensures the Cloudflare
    HTML case yields the friendly message.
    - unexpected_status_non_html_is_unchanged confirms plain-text 403s still
    return the raw body.
    
    ### Testing
    
    - cargo build -p codex-cli
    - cargo test -p codex-core
    - just fix -p codex-core
    - cargo test --all-features
    
    ---------
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • [App-server] Implement account/read endpoint (#6336)
    This PR does two things:
    1. add a new function in core that maps the core-internal plan type to
    the external plan type;
    2. implement account/read that get account status (v2 of
    `getAuthStatus`).
  • Prefer wait_for_event over wait_for_event_with_timeout. (#6346)
    No need to specify the timeout in most cases.
  • Remove shell tool when unified exec is enabled (#6345)
    Also drop streameable shell that's just an alias for unified exec.
  • Don't retry "insufficient_quota" errors (#6340)
    This PR makes an "insufficient quota" error fatal so we don't attempt to
    retry it multiple times in the agent loop.
    
    We have multiple bug reports from users about intermittent retry
    behaviors, and this could explain some of them. With this change, we'll
    eliminate the retries and surface a clear error message.
    
    The PR is a nearly identical copy of [this
    PR](https://github.com/openai/codex/pull/4837) contributed by
    @abimaelmartell. The original PR has gone stale. Rather than wait for
    the contributor to resolve merge conflicts, I wanted to get this change
    in.
  • core: widen sandbox to allow certificate ops when network is enabled (#5980)
    This allows `gh api` to work in the workspace-write sandbox w/ network
    enabled. Without this we see e.g.
    
    ```
    $ codex debug seatbelt --full-auto gh api repos/openai/codex/pulls --paginate -X GET -F state=all
    Get "https://api.github.com/repos/openai/codex/pulls?per_page=100&state=all": tls: failed to verify certificate: x509: OSStatus -26276
    ```
  • Windows Sandbox: Show Everyone-writable directory warning (#6283)
    Show a warning when Auto Sandbox mode becomes enabled, if we detect
    Everyone-writable directories, since they cannot be protected by the
    current implementation of the Sandbox.
    
    This PR also includes changes to how we detect Everyone-writable to be
    *much* faster
  • Fixes intermittent test failures in CI (#6282)
    I'm seeing two tests fail intermittently in CI. This PR attempts to
    address (or at least mitigate) the flakiness.
    
    * summarize_context_three_requests_and_instructions - The test snapshots
    server.received_requests() immediately after observing TaskComplete.
    Because the OpenAI /v1/responses call is streamed, the HTTP request can
    still be draining when that event fires, so wiremock occasionally
    reports only two captured requests. Fix is to wait for async activity to
    complete.
    * archive_conversation_moves_rollout_into_archived_directory - times out
    on a slow CI run. Mitigation is to increase timeout value from 10s to
    20s.
  • [app-server] feat: v2 Thread APIs (#6214)
    Implements:
    ```
    thread/list
    thread/start
    thread/resume
    thread/archive
    ```
    
    along with their integration tests. These are relatively light wrappers
    around the existing core logic, and changes to core logic are minimal.
    
    However, an improvement made for developer ergonomics:
    - `thread/start` and `thread/resume` automatically attaches a
    conversation listener internally, so clients don't have to make a
    separate `AddConversationListener` call like they do today.
    
    For consistency, also updated `model/list` and `feedback/upload` (naming
    conventions, list API params).
  • Improved token refresh handling to address "Re-connecting" behavior (#6231)
    Currently, when the access token expires, we attempt to use the refresh
    token to acquire a new access token. This works most of the time.
    However, there are situations where the refresh token is expired,
    exhausted (already used to perform a refresh), or revoked. In those
    cases, the current logic treats the error as transient and attempts to
    retry it repeatedly.
    
    This PR changes the token refresh logic to differentiate between
    permanent and transient errors. It also changes callers to treat the
    permanent errors as fatal rather than retrying them. And it provides
    better error messages to users so they understand how to address the
    problem. These error messages should also help us further understand why
    we're seeing examples of refresh token exhaustion.
    
    Here is the error message in the CLI. The same text appears within the
    extension.
    
    <img width="863" height="38" alt="image"
    src="https://github.com/user-attachments/assets/7ffc0d08-ebf0-4900-b9a9-265064202f4f"
    />
    
    I also correct the spelling of "Re-connecting", which shouldn't have a
    hyphen in it.
    
    Testing: I manually tested these code paths by adding temporary code to
    programmatically cause my refresh token to be exhausted (by calling the
    token refresh endpoint in a tight loop more than 50 times). I then
    simulated an access token expiration, which caused the token refresh
    logic to be invoked. I confirmed that the updated logic properly handled
    the error condition.
    
    Note: We earlier discussed the idea of forcefully logging out the user
    at the point where token refresh failed. I made several attempts to do
    this, and all of them resulted in a bad UX. It's important to surface
    this error to users in a way that explains the problem and tells them
    that they need to log in again. We also previously discussed deleting
    the auth.json file when this condition is detected. That also creates
    problems because it effectively changes the auth status from logged in
    to logged out, and this causes odd failures and inconsistent UX. I think
    it's therefore better not to delete auth.json in this case. If the user
    closes the CLI or VSCE and starts it again, we properly detect that the
    access token is expired and the refresh token is "dead", and we force
    the user to go through the login flow at that time.
    
    This should address aspects of #6191, #5679, and #5505
  • refactor Conversation history file into its own directory (#6229)
    This is just a refactor of `conversation_history` file by breaking it up
    into multiple smaller ones with helper. This refactor will help us move
    more functionality related to context management here. in a clean way.
  • allow codex to be run from pid 1 (#4200)
    Previously it was not possible for codex to run commands as the init
    process (pid 1) in linux. Commands run in containers tend to see their
    own pid as 1. See https://github.com/openai/codex/issues/4198
    
    This pr implements the solution mentioned in that issue.
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • fix(core): load custom prompts from symlinked Markdown files (#3643)
    - Discover prompts via fs::metadata to follow symlinks
    
    - Add Unix-only symlink test in custom_prompts.rs
    
    - Update docs/prompts.md to mention symlinks
    
    Fixes #3637
    
    ---------
    
    Signed-off-by: Soroush Yousefpour <h.yusefpour@gmail.com>
    Co-authored-by: dedrisian-oai <dedrisian@openai.com>
    Co-authored-by: Eric Traut <etraut@openai.com>
  • fix: Update the deprecation message to link to the docs (#6211)
    The deprecation message is currently a bit confusing. Users may not
    understand what is `[features].x`. I updated the docs and the
    deprecation message for more guidance.
    
    ---------
    
    Co-authored-by: Gabriel Peal <gpeal@users.noreply.github.com>
  • ignore deltas in codex_delegate (#6208)
    ignore legacy deltas in codex-delegate to avoid this
    [issue](https://github.com/openai/codex/pull/6202).
  • [App-server] v2 for account/updated and account/logout (#6175)
    V2 for `account/updated` and `account/logout` for app server. correspond
    to old `authStatusChange` and `LogoutChatGpt` respectively. Followup PRs
    will make other v2 endpoints call `account/updated` instead of
    `authStatusChange` too.
  • Fix is_api_message to correctly exclude reasoning messages (#6156)
    ## Problem
    
    The `is_api_message` function in `conversation_history.rs` had a
    misalignment between its documentation and implementation:
    
    - **Comment stated**: "Anything that is not a system message or
    'reasoning' message is considered an API message"
    - **Code behavior**: Was returning `true` for `ResponseItem::Reasoning`,
    meaning reasoning messages were incorrectly treated as API messages
    
    This inconsistency could lead to reasoning messages being persisted in
    conversation history when they should be filtered out.
    
    ## Root Cause
    
    Investigation revealed that reasoning messages are explicitly excluded
    throughout the codebase:
    
    1. **Chat completions API** (lines 267-272 in `chat_completions.rs`)
    omits reasoning from conversation history:
       ```rust
       ResponseItem::Reasoning { .. } | ResponseItem::Other => {
           // Omit these items from the conversation history.
           continue;
       }
       ```
    
    2. **Existing tests** like `drops_reasoning_when_last_role_is_user` and
    `ignores_reasoning_before_last_user` validate that reasoning should be
    excluded from API payloads
    
    ## Solution
    
    Fixed the `is_api_message` function to align with its documentation and
    the rest of the codebase:
    
    ```rust
    // Before: Reasoning was incorrectly returning true
    ResponseItem::Reasoning { .. } | ResponseItem::WebSearchCall { .. } => true,
    
    // After: Reasoning correctly returns false  
    ResponseItem::WebSearchCall { .. } => true,
    ResponseItem::Reasoning { .. } | ResponseItem::Other => false,
    ```
    
    ## Testing
    
    - Enhanced existing test to verify reasoning messages are properly
    filtered out
    - All 264 core tests pass, including 8 chat completions tests that
    validate reasoning behavior
    - No regressions introduced
    
    This ensures reasoning messages are consistently excluded from API
    message processing across the entire codebase.
  • Fixed notify handler so it passes correct input_messages details (#6143)
    This fixes bug #6121. 
    
    The `input_messages` field passed to the notify handler is currently
    empty because the logic is incorrectly including the OutputText rather
    than InputText. I've fixed that and added proper filtering to remove
    messages associated with AGENTS.md and other context injected by the
    harness.
    
    Testing: I wrote a notify handler and verified that the user prompt is
    correctly passed through to the handler.
  • log sandbox commands to $CODEX_HOME instead of cwd (#6171)
    Logging commands in the Windows Sandbox is temporary, but while we are
    doing it, let's always write to CODEX_HOME instead of dirtying the cwd.
  • feat: add the time after aborting (#5996)
    Tell the model how much time passed after the user aborted the call.
  • Do not skip trust prompt on Windows if sandbox is enabled. (#6167)
    If the experimental windows sandbox is enabled, the trust prompt should
    show on Windows.
  • fix: improve usage URLs in status card and snapshots (#6111)
    Hi OpenAI Codex team, currently "Visit chatgpt.com/codex/settings/usage
    for up-to-date information on rate limits and credits" message in status
    card and error messages. For now, without the "https://" prefix, the
    link cannot be clicked directly from most terminals or chat interfaces.
    
    <img width="636" height="127" alt="Screenshot 2025-11-02 at 22 47 06"
    src="https://github.com/user-attachments/assets/5ea11e8b-fb74-451c-85dc-f4d492b2678b"
    />
    
    ---
    
    The fix is intent to improve this issue:
    
    - It makes the link clickable in terminals that support it, hence better
    accessibility
    - It follows standard URL formatting practices
    - It maintains consistency with other links in the application (like the
    existing "https://openai.com/chatgpt/pricing" links)
    
    Thank you!
  • Fix incorrect "deprecated" message about experimental config key (#6131)
    When I enable `experimental_sandbox_command_assessment`, I get an
    incorrect deprecation warning: "experimental_sandbox_command_assessment
    is deprecated. Use experimental_sandbox_command_assessment instead."
    
    This PR fixes this error.
  • Changes to sandbox command assessment feature based on initial experiment feedback (#6091)
    * Removed sandbox risk categories; feedback indicates that these are not
    that useful and "less is more"
    * Tweaked the assessment prompt to generate terser answers
    * Fixed bug in orchestrator that prevents this feature from being
    exposed in the extension
  • Parse the Azure OpenAI rate limit message (#5956)
    Fixes #4161
    
    Currently Codex uses a regex to parse the "Please try again in 1.898s"
    OpenAI-style rate limit message, so that it can wait the correct
    duration before retrying. Azure OpenAI returns a different error that
    looks like "Rate limit exceeded. Try again in 35 seconds."
    
    This PR extends the regex and parsing code to match in a more fuzzy
    manner, handling anything matching the pattern "try again in
    \<duration>\<unit>".
  • feat: compactor 2 (#6027)
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • Add warning on compact (#6052)
    This PR introduces the ability for `core` to send `warnings` as it can
    send `errors. It also sends a warning on compaction.
    
    <img width="811" height="187" alt="image"
    src="https://github.com/user-attachments/assets/0947a42d-b720-420d-b7fd-115f8a65a46a"
    />
  • chore: Add shell serialization tests for json (#6043)
    ## Summary
    Can never have enough tests on this code path - checking that json
    inside a shell call is deserialized correctly.
    
    ## Tests
    - [x] These are tests 😎
  • Truncate total tool calls text (#5979)
    Put a cap on the aggregate output of text content on tool calls.
    
    ---------
    
    Co-authored-by: Gabriel Peal <gpeal@users.noreply.github.com>