Commit Graph

465 Commits

  • feat: add support for --sandbox flag (#1476)
    On a high-level, we try to design `config.toml` so that you don't have
    to "comment out a lot of stuff" when testing different options.
    
    Previously, defining a sandbox policy was somewhat at odds with this
    principle because you would define the policy as attributes of
    `[sandbox]` like so:
    
    ```toml
    [sandbox]
    mode = "workspace-write"
    writable_roots = [ "/tmp" ]
    ```
    
    but if you wanted to temporarily change to a read-only sandbox, you
    might feel compelled to modify your file to be:
    
    ```toml
    [sandbox]
    mode = "read-only"
    # mode = "workspace-write"
    # writable_roots = [ "/tmp" ]
    ```
    
    Technically, commenting out `writable_roots` would not be strictly
    necessary, as `mode = "read-only"` would ignore `writable_roots`, but
    it's still a reasonable thing to do to keep things tidy.
    
    Currently, the various values for `mode` do not support that many
    attributes, so this is not that hard to maintain, but one could imagine
    this becoming more complex in the future.
    
    In this PR, we change Codex CLI so that it no longer recognizes
    `[sandbox]`. Instead, it introduces a top-level option, `sandbox_mode`,
    and `[sandbox_workspace_write]` is used to further configure the sandbox
    when when `sandbox_mode = "workspace-write"` is used:
    
    ```toml
    sandbox_mode = "workspace-write"
    
    [sandbox_workspace_write]
    writable_roots = [ "/tmp" ]
    ```
    
    This feels a bit more future-proof in that it is less tedious to
    configure different sandboxes:
    
    ```toml
    sandbox_mode = "workspace-write"
    
    [sandbox_read_only]
    # read-only options here...
    
    [sandbox_workspace_write]
    writable_roots = [ "/tmp" ]
    
    [sandbox_danger_full_access]
    # danger-full-access options here...
    ```
    
    In this scheme, you never need to comment out the configuration for an
    individual sandbox type: you only need to redefine `sandbox_mode`.
    
    Relatedly, previous to this change, a user had to do `-c
    sandbox.mode=read-only` to change the mode on the command line. With
    this change, things are arguably a bit cleaner because the equivalent
    option is `-c sandbox_mode=read-only` (and now `-c
    sandbox_workspace_write=...` can be set separately).
    
    Though more importantly, we introduce the `-s/--sandbox` option to the
    CLI, which maps directly to `sandbox_mode` in `config.toml`, making
    config override behavior easier to reason about. Moreover, as you can
    see in the updates to the various Markdown files, it is much easier to
    explain how to configure sandboxing when things like `--sandbox
    read-only` can be used as an example.
    
    Relatedly, this cleanup also made it straightforward to add support for
    a `sandbox` option for Codex when used as an MCP server (see the changes
    to `mcp-server/src/codex_tool_config.rs`).
    
    Fixes https://github.com/openai/codex/issues/1248.
  • docs: update README to include npm install again (#1475)
    v0.2.0 of https://www.npmjs.com/package/@openai/codex now runs the Rust
    CLI, so it makes sense to bring back the instructions to use `npm i -g
    @openai/codex`.
    
    In most places, I list `npm install` before `brew install` because I
    believe `npm` is more readily available, though I in the more detailed
    part of the documentation, I note that `brew install` will download
    fewer bytes, and in that sense, is preferred.
  • chore: normalize repository.url in package.json (#1474)
    I got this as a warning when doing `npm publish --dry-run`, so I ran
    `npm pkg fix` to create this PR, as instructed.
  • Fix Unicode handling in chat_composer "@" token detection (#1467)
    ## Issues Fixed
    
    - **Primary Issue (#1450)**: Unicode cursor positioning was incorrect
    due to mixing character positions with byte positions
    - **Additional Issue**: Full-width spaces (CJK whitespace like " ")
    weren't properly handled as token boundaries
    - ref:
    https://doc.rust-lang.org/std/primitive.char.html#method.is_whitespace
    
    ---------
    
    Co-authored-by: Michael Bolin <bolinfest@gmail.com>
  • feat: support custom HTTP headers for model providers (#1473)
    This adds support for two new model provider config options:
    
    - `http_headers` for hardcoded (key, value) pairs
    - `env_http_headers` for headers whose values should be read from
    environment variables
    
    This also updates the built-in `openai` provider to use this feature to
    set the following headers:
    
    - `originator` => `codex_cli_rs`
    - `version` => [CLI version]
    - `OpenAI-Organization` => `OPENAI_ORGANIZATION` env var
    - `OpenAI-Project` => `OPENAI_PROJECT` env var
    
    for consistency with the TypeScript implementation:
    
    
    https://github.com/openai/codex/blob/bd5a9e8ba96c7d9c58ecaf5e61ec62d14ac6378d/codex-cli/src/utils/agent/agent-loop.ts#L321-L329
    
    While here, this also consolidates some logic that was duplicated across
    `client.rs` and `chat_completions.rs` by introducing
    `ModelProviderInfo.create_request_builder()`.
    
    Resolves https://github.com/openai/codex/discussions/1152
  • chore: update release scripts for the TypeScript CLI (#1472)
    This introduces two changes to make a quick fix so we can deploy the
    Rust CLI for `0.2.0` of `@openai/codex` on npm:
    
    - Updates `WORKFLOW_URL` to point to
    https://github.com/openai/codex/actions/runs/15981617627, which is the
    GitHub workflow run used to create the binaries for the `0.2.0` release
    we published to Homebrew.
    - Adds a `--version` option to `stage_release.sh` to specify what the
    `version` field in the `package.json` will be.
    
    Locally, I ran the following:
    
    ```
    ./codex-cli/scripts/stage_release.sh --native --version 0.2.0
    ```
    
    Previously, we only used the `--native` flag to publish to the `native`
    tag of `@openai/codex` (e.g., `npm publish --tag native`), but we should
    just publish this as the default tag for `0.2.0` to be consistent with
    what is in Homebrew.
    
    We can still publish one "final" version of the TypeScript CLI as 0.1.x
    later.
    
    Under the hood, this release will still contain `dist/cli.js`,
    `bin/codex-linux-sandbox-x64`, and `bin/codex-x86_64-apple-darwin`,
    which are not strictly necessary, but we'll fix that in `0.3.0`.
  • docs: update documentation to reflect Rust CLI release (#1440)
    As promised on https://github.com/openai/codex/discussions/1405, we are
    making the first official release of the Rust CLI as v0.2.0. As part of
    this move, we are making it available in Homebrew:
    
    https://github.com/Homebrew/homebrew-core/pull/228615
    
    Ultimately, we also plan to continue to make the CLI available in npm,
    as well, though brew is a bit nicer in that `brew install` will download
    only the binary for your platform whereas an npm module is expected to
    contain the binaries for _all_ supported platforms, so it is a bit more
    heavyweight.
    
    A big part of this change is updating the root `README.md` to document
    the behavior of the Rust CLI, which differs in a number of ways from the
    TypeScript CLI. The existing `README.md` is moved to
    `codex-cli/README.md` as part of this PR, as it is still applicable to
    that folder.
    
    As this is still early days for the Rust CLI, I encourage folks to
    provide feedback on the command line flags and configuration options.
  • fix: softprops/action-gh-release@v2 should use existing tag instead of creating a new tag (#1436)
    https://github.com/Homebrew/homebrew-core/pull/228521 details the issues
    I was having with the **Source code (tar.gz)** artifact for our GitHub
    releases not being quite right. I landed these PRs as stabs in the dark
    to fix this:
    
    - https://github.com/openai/codex/pull/1423
    - https://github.com/openai/codex/pull/1430
    
    Based on the insights from
    https://github.com/Homebrew/homebrew-core/pull/228521, I think those
    were wrong and the real problem was this:
    
    
    https://github.com/openai/codex/blob/6dad5c3b1799ac18f7c76a9612f24936682b3c1d/.github/workflows/rust-release.yml#L162
    
    That is, I was manufacturing a new tag name on the fly instead of using
    the existing one.
    
    This PR reverts #1423 and #1430 and hopefully fixes how `tag_name` is
    set for the `softprops/action-gh-release@v2` step so the **Source code
    (tar.gz)** includes the correct files. Assuming this works, this should
    make the Homebrew formula straightforward.
  • feat: add query_params option to ModelProviderInfo to support Azure (#1435)
    As discovered in https://github.com/openai/codex/issues/1365, the Azure
    provider needs to be able to specify `api-version` as a query param, so
    this PR introduces a generic `query_params` option to the
    `model_providers` config so that an Azure provider can be defined as
    follows:
    
    ```toml
    [model_providers.azure]
    name = "Azure"
    base_url = "https://YOUR_PROJECT_NAME.openai.azure.com/openai"
    env_key = "AZURE_OPENAI_API_KEY"
    query_params = { api-version = "2025-04-01-preview" }
    ```
    
    This PR also updates the docs with this example.
    
    While here, we also update `wire_api` to default to `"chat"`, as that is
    likely the common case for someone defining an external provider.
    
    Fixes https://github.com/openai/codex/issues/1365.
  • chore: fix Rust release process so generated .tar.gz source works with Homebrew (#1423)
    Looking at existing releases such as
    https://github.com/openai/codex/releases/tag/codex-rs-b289c9207090b2e27494545d7b5404e063bd86f3-1-rust-v0.1.0-alpha.4,
    the `.tar.gz` for the source code still seems to have `0.0.0` as the
    `version` in `codex-rs/Cargo.toml` instead of what the tag seems to say
    it should have:
    
    
    https://github.com/openai/codex/blob/b289c9207090b2e27494545d7b5404e063bd86f3/codex-rs/Cargo.toml#L21
    
    ChatGPT claims:
    
    > When GitHub generates the Source code (tar.gz) archive for a tag:
    	•	It uses the commit the tag points to.
    • But in some cases (e.g., shallow clones, GitHub CI, or local tools
    that only clone the default branch), that commit may not be included,
    and you might get an outdated view or nothing at all depending on how
    it’s fetched.
    	
    Trying this recommended fix.
  • fix: support pre-release identifiers in tags (#1422)
    Had to update the regex in the GitHub workflow to allow suffixes like
    `-alpha.4`.
    
    Successfully ran:
    
    ```
    ./scripts/create_github_release.sh 0.1.0-alpha.4
    ```
    
    to create
    https://github.com/openai/codex/releases/tag/codex-rs-b289c9207090b2e27494545d7b5404e063bd86f3-1-rust-v0.1.0-alpha.4
    
    and verified that when I run `codex --version`, it prints `codex-cli
    0.1.0-alpha.4`.
  • feat: introduce --compute-indices flag to codex-file-search (#1419)
    This is a small quality-of-life feature, the addition of
    `--compute-indices` to the CLI, which, if enabled, will compute and set
    the `indices` field for each `FileMatch` returned by `run()`. Note we
    only bother to compute `indices` once we have the top N results because
    there could be a lot of intermediate "top N" results during the search
    that are ultimately discarded.
    
    When set, the indices are included in the JSON output when `--json` is
    specified and the matching indices are displayed in bold when `--json`
    is not specified.
  • feat: add support for @ to do file search (#1401)
    Introduces support for `@` to trigger a fuzzy-filename search in the
    composer. Under the hood, this leverages
    https://crates.io/crates/nucleo-matcher to do the fuzzy matching and
    https://crates.io/crates/ignore to build up the list of file candidates
    (so that it respects `.gitignore`).
    
    For simplicity (at least for now), we do not do any caching between
    searches like VS Code does for its file search:
    
    
    https://github.com/microsoft/vscode/blob/1d89ed699b2e924d418c856318a3e12bca67ff3a/src/vs/workbench/services/search/node/rawSearchService.ts#L212-L218
    
    Because we do not do any caching, I saw queries take up to three seconds
    on large repositories with hundreds of thousands of files. To that end,
    we do not perform searches synchronously on each keystroke, but instead
    dispatch an event to do the search on a background thread that
    asynchronously reports back to the UI when the results are available.
    This is largely handled by the `FileSearchManager` introduced in this
    PR, which also has logic for debouncing requests so there is at most one
    search in flight at a time.
    
    While we could potentially polish and tune this feature further, it may
    already be overengineered for how it will be used, in practice, so we
    can improve things going forward if it turns out that this is not "good
    enough" in the wild.
    
    Note this feature does not work like `@` in the TypeScript CLI, which
    was more like directory-based tab completion. In the Rust CLI, `@`
    triggers a full-repo fuzzy-filename search.
    
    Fixes https://github.com/openai/codex/issues/1261.
  • feat: make file search cancellable (#1414)
    Update `run()` to take `cancel_flag: Arc<AtomicBool>` that the worker
    threads will periodically check to see if it is `true`, exiting early
    (and returning empty results) if so.
  • chore: change arg from PathBuf to &Path (#1409)
    Caller no longer needs to clone a `PathBuf`: can just pass `&Path`.
  • chore: change built_in_model_providers so "openai" is the only "bundled" provider (#1407)
    As we are [close to releasing the Rust CLI
    beta](https://github.com/openai/codex/discussions/1405), for the moment,
    let's take a more neutral stance on what it takes to be a "built-in"
    provider.
    
    * For example, there seems to be a discrepancy around what the "right"
    configuration for Gemini is: https://github.com/openai/codex/pull/881
    * And while the current list of "built-in" providers are all arguably
    "well-known" names, this raises a question of what to do about
    potentially less familiar providers, such as
    https://github.com/openai/codex/pull/1142. Do we just accept every pull
    request like this, or is there some criteria a provider has to meet to
    "qualify" to be bundled with Codex CLI?
    
    I think that if we can establish clear ground rules for being a built-in
    provider, then we can bring this back. But until then, I would rather
    take a minimalist approach because if we decided to reverse our position
    later, it would break folks who were depending on the presence of the
    built-in providers.
  • Handle Ctrl+C quit when idle (#1402)
    ## Summary
    - show `Ctrl+C to quit` hint when pressing Ctrl+C with no active task
    - exiting with Ctrl+C if the hint is already visible
    - clear the hint when tasks begin or other keys are pressed
    
    
    https://github.com/user-attachments/assets/931e2d7c-1c80-4b45-9908-d119f74df23c
    
    
    
    ------
    https://chatgpt.com/s/cd_685ec8875a308191beaa95886dc1379e
    
    Fixes #1245
  • fix: add tiebreaker logic for paths when scores are equal (#1400)
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/1400).
    * #1401
    * __->__ #1400
  • feat: add support for /diff command (#1389)
    Adds support for a `/diff` command comparable to the one available in
    the TypeScript CLI.
    
    <img width="1103" alt="Screenshot 2025-06-26 at 12 31 33 PM"
    src="https://github.com/user-attachments/assets/5dc646ca-301f-41ff-92a7-595c68db64b6"
    />
    
    While here, changed the `SlashCommand` enum so the declared variant
    order is the order the commands appear in the popup menu. This way,
    `/toggle-mouse-mode` is listed last, as it is the least likely to be
    used.
    
    Fixes https://github.com/openai/codex/issues/1253.
  • [Rust] Allow resuming a session that was killed with ctrl + c (#1387)
    Previously, if you ctrl+c'd a conversation, all subsequent turns would
    400 because the Responses API never got a response for one of its call
    ids. This ensures that if we aren't sending a call id by hand, we
    generate a synthetic aborted call.
    
    Fixes #1244 
    
    
    https://github.com/user-attachments/assets/5126354f-b970-45f5-8c65-f811bca8294a
  • feat: show number of tokens remaining in UI (#1388)
    When using the OpenAI Responses API, we now record the `usage` field for
    a `"response.completed"` event, which includes metrics about the number
    of tokens consumed. We also introduce `openai_model_info.rs`, which
    includes current data about the most common OpenAI models available via
    the API (specifically `context_window` and `max_output_tokens`). If
    Codex does not recognize the model, you can set `model_context_window`
    and `model_max_output_tokens` explicitly in `config.toml`.
    
    When then introduce a new event type to `protocol.rs`, `TokenCount`,
    which includes the `TokenUsage` for the most recent turn.
    
    Finally, we update the TUI to record the running sum of tokens used so
    the percentage of available context window remaining can be reported via
    the placeholder text for the composer:
    
    ![Screenshot 2025-06-25 at 11 20
    55 PM](https://github.com/user-attachments/assets/6fd6982f-7247-4f14-84b2-2e600cb1fd49)
    
    We could certainly get much fancier with this (such as reporting the
    estimated cost of the conversation), but for now, we are just trying to
    achieve feature parity with the TypeScript CLI.
    
    Though arguably this improves upon the TypeScript CLI, as the TypeScript
    CLI uses heuristics to estimate the number of tokens used rather than
    using the `usage` information directly:
    
    
    https://github.com/openai/codex/blob/296996d74e345b1b05d8c3451a06ace21c5ada96/codex-cli/src/utils/approximate-tokens-used.ts#L3-L16
    
    Fixes https://github.com/openai/codex/issues/1242
  • feat: standalone file search CLI (#1386)
    Standalone fuzzy filename search library that should be helpful in
    addressing https://github.com/openai/codex/issues/1261.
  • feat: add --dangerously-bypass-approvals-and-sandbox (#1384)
    This PR reworks `assess_command_safety()` so that the combination of
    `AskForApproval::Never` and `SandboxPolicy::DangerFullAccess` ensures
    that commands are run without _any_ sandbox and the user should never be
    prompted. In turn, it adds support for a new
    `--dangerously-bypass-approvals-and-sandbox` flag (that cannot be used
    with `--approval-policy` or `--full-auto`) that sets both of those
    options.
    
    Fixes https://github.com/openai/codex/issues/1254
  • chore: rename AskForApproval::UnlessAllowListed to AskForApproval::UnlessTrusted (#1385)
    We could just rename to `Untrusted` instead of `UnlessTrusted`, but I
    think `AskForApproval::UnlessTrusted` reads a bit better.
  • chore: improve docstring for --full-auto (#1379)
    Reference `-c sandbox.mode=workspace-write` in the docstring and users
    can read the config docs for `sandbox` for more information.
  • chore: rename unless-allow-listed to untrusted (#1378)
    For the `approval_policy` config option, renames `unless-allow-listed`
    to `untrusted`. In general, when it comes to exec'ing commands, I think
    "trusted" is a more accurate term than "safe."
    
    Also drops the `AskForApproval::AutoEdit` variant, as we were not really
    making use of it, anyway.
    
    Fixes https://github.com/openai/codex/issues/1250.
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/1378).
    * #1379
    * __->__ #1378
  • fix: pretty-print the sandbox config in the TUI/exec modes (#1376)
    Now that https://github.com/openai/codex/pull/1373 simplified the
    sandbox config, we can print something much simpler in the TUI (and in
    `codex exec`) to summarize the sandbox config.
    
    Before:
    
    ![Screenshot 2025-06-24 at 5 45
    52 PM](https://github.com/user-attachments/assets/b7633efb-a619-43e1-9abe-7bb0be2d0ec0)
    
    With this change:
    
    ![Screenshot 2025-06-24 at 5 46
    44 PM](https://github.com/user-attachments/assets/8d099bdd-a429-4796-a08d-70931d984e4f)
    
    For reference, my `config.toml` contains:
    
    ```
    [sandbox]
    mode = "workspace-write"
    writable_roots = ["/tmp", "/Users/mbolin/.pyenv/shims"]
    ```
    
    Fixes https://github.com/openai/codex/issues/1248
  • chore: install just in the devcontainer for Linux development (#1375)
    Apparently `just` was added to `apt` in Ubuntu 24, so this required
    updating the Ubuntu version in the `Dockerfile` to make it so we could
    simply `apt install just`.
    
    Though then that caused a conflict with the custom `dev` user we were
    using, though the end result seems simpler since now we just use the
    default `ubuntu` user provided by Ubuntu 24.
  • chore: install clippy and rustfmt in the devcontainer for Linux development (#1374)
    I discovered it was difficult to do development in the devcontainer
    without these tools available.
  • feat: redesign sandbox config (#1373)
    This is a major redesign of how sandbox configuration works and aims to
    fix https://github.com/openai/codex/issues/1248. Specifically, it
    replaces `sandbox_permissions` in `config.toml` (and the
    `-s`/`--sandbox-permission` CLI flags) with a "table" with effectively
    three variants:
    
    ```toml
    # Safest option: full disk is read-only, but writes and network access are disallowed.
    [sandbox]
    mode = "read-only"
    
    # The cwd of the Codex task is writable, as well as $TMPDIR on macOS.
    # writable_roots can be used to specify additional writable folders.
    [sandbox]
    mode = "workspace-write"
    writable_roots = []  # Optional, defaults to the empty list.
    network_access = false  # Optional, defaults to false.
    
    # Disable sandboxing: use at your own risk!!!
    [sandbox]
    mode = "danger-full-access"
    ```
    
    This should make sandboxing easier to reason about. While we have
    dropped support for `-s`, the way it works now is:
    
    - no flags => `read-only`
    - `--full-auto` => `workspace-write`
    - currently, there is no way to specify `danger-full-access` via a CLI
    flag, but we will revisit that as part of
    https://github.com/openai/codex/issues/1254
    
    Outstanding issue:
    
    - As noted in the `TODO` on `SandboxPolicy::is_unrestricted()`, we are
    still conflating sandbox preferences with approval preferences in that
    case, which needs to be cleaned up.
  • add: responses api support for azure (#1321)
    - Use Responses API for Azure provider endpoints
    - Added a unit test to catch regression on the change from
    `/chat/completions` to `/responses`
    - Updated the default AOAI api version from `2025-03-01-preview` to
    `2025-04-01-preview` to avoid user/400 errors due to missing summary
    support in the March API version.
    - Changes have been tested locally on AOAI endpoints
  • feat(ts): provider‑specific API‑key discovery and clearer Azure guidance (#1324)
    ## Summary
    
    This PR refactors the Codex CLI authentication flow so that
    **non-OpenAI** providers (for example **azure**, or any future addition)
    can supply their API key through a dedicated environment variable
    without triggering the OpenAI login flow.
    
    Key behaviours introduced:
    
    * When `provider !== "openai"` the CLI consults `src/utils/providers.ts`
    to locate the correct environment variable (`AZURE_OPENAI_API_KEY`,
    `GEMINI_API_KEY`, and so on) before considering any interactive login.
    * Credit redemption (`--free`) and PKCE login now run **only** when the
    provider is OpenAI, eliminating unwanted browser prompts for Azure and
    others.
    * User-facing error messages are revamped to guide Azure users to
    **[https://ai.azure.com/](https://ai.azure.com)** and show the exact
    variable name they must set.
    * All code paths still export `OPENAI_API_KEY` so legacy scripts
    continue to operate unchanged.
    
    ---
    
    ## Example `config.json`
    
    ```jsonc
    {
      "model": "codex-mini",
      "provider": "azure",
      "providers": {
        "azure": {
          "name": "AzureOpenAI",
          "baseURL": "https://ai-<project-name>.openai.azure.com/openai",
          "envKey": "AZURE_OPENAI_API_KEY"
        }
      },
      "history": {
        "maxSize": 1000,
        "saveHistory": true,
        "sensitivePatterns": []
      }
    }
    ```
    
    With this file in `~/.codex/config.json`, a single command line is
    enough:
    
    ```bash
    export AZURE_OPENAI_API_KEY="<your-key>"
    codex "Hello from Azure"
    ```
    
    No browser window opens, and the CLI works in entirely non-interactive
    mode.
    
    ---
    
    ## Rationale
    
    The new flow enables Codex to run **asynchronously** in sandboxed
    environments such as GitHub Actions pipelines. By passing `--provider
    azure` (or setting it in `config.json`) and exporting the correct key,
    CI/CD jobs can invoke Codex without any ChatGPT-style login or PKCE
    round-trip. This unlocks fully automated testing and deployment
    scenarios.
    
    ---
    
    ## What’s changed
    
    | File | Type | Description |
    | ------------------------ | ------------------- |
    -----------------------------------------------------------------------------------------------------------------------------
    |
    | `codex-cli/src/cli.tsx` | **feat / refactor** | +43 / -20 lines.
    Imports `providers`, adds early provider-specific key lookup, gates
    `--free` redemption, rewrites help text. |
    | `src/utils/providers.ts` | **chore** | Now consumed by CLI for env-var
    discovery. |
    
    ---
    
    ## How to test
    
    ```bash
    # Azure example
    export AZURE_OPENAI_API_KEY="<your-key>"
    codex --provider azure "Automated run in CI"
    
    # OpenAI example (unchanged behaviour)
    codex --provider openai --login "Standard OpenAI flow"
    ```
    
    Expected outcomes:
    
    * Azure and other provider paths are non-interactive when provider flag
    is passed.
    * The CLI always sets `OPENAI_API_KEY` for backward compatibility.
    
    ---
    
    ## Checklist
    
    * [x] Logic behind provider-specific env-var lookup added.
    * [x] Redundant OpenAI login steps removed for other providers.
    * [x] Unit tests cover new branches.
    * [x] README and sample config updated.
    * [x] CI passes on all supported Node versions.
    
    ---
    
    **Related work**
    
    * #92
    * #769 
    * #1321
    
    
    
    I have read the CLA Document and I hereby sign the CLA.
  • docs: update codex-rs/README.md to list new features in the Rust CLI (#1267)
    Let users know about what the Rust CLI supports that the TypeScript CLI
    doesn't!
  • codex-rs: Rename /clear to /new, make it start an entirely new chat (#1264)
    I noticed that `/clear` wasn't fully clearing chat history; it would
    clear the chat history widgets _in the UI_, but the LLM still had access
    to information from previous messages.
    
    This PR renames `/clear` to `/new` for clarity as per Michael's
    suggestion, resetting `app_state` to a fresh `ChatWidget`.
  • chore: ensure next Node.js release includes musl binaries for arm64 Linux (#1232)
    Target a workflow with more recent binary artifacts.
  • fix: use aarch64-unknown-linux-musl instead of aarch64-unknown-linux-gnu (#1228)
    Now that we have published a GitHub Release that contains arm64 musl
    artifacts for Linux, update the following scripts to take advantage of
    them:
    
    - `dotslash-config.json` now uses musl artifacts for the `linux-aarch64`
    target
    - `install_native_deps.sh` for the TypeScript CLI now includes
    `codex-linux-sandbox-aarch64-unknown-linux-musl` instead of
    `codex-linux-sandbox-aarch64-unknown-linux-gnu` for sandboxing
    - `codex-cli/bin/codex.js` now checks for `aarch64-unknown-linux-musl`
    artifacts instead of `aarch64-unknown-linux-gnu` ones
  • fix: include codex-linux-sandbox-aarch64-unknown-linux-musl in the set of release artifacts (#1230)
    This was missed in https://github.com/openai/codex/pull/1225. Once we
    create a new GitHub Release with this change, we can use the URL from
    the workflow that triggered the release in
    https://github.com/openai/codex/pull/1228.
  • fix: support arm64 build for Linux (#1225)
    Users were running into issues with glibc mismatches on arm64 linux. In
    the past, we did not provide a musl build for arm64 Linux because we had
    trouble getting the openssl dependency to build correctly. Though today
    I just tried the same trick in `Cargo.toml` that we were doing for
    `x86_64-unknown-linux-musl` (using `openssl-sys` with `features =
    ["vendored"]`), so I'm not sure what problem we had in the past the
    builds "just worked" today!
    
    Though one tweak that did have to be made is that the integration tests
    for Seccomp/Landlock empirically require longer timeouts on arm64 linux,
    or at least on the `ubuntu-24.04-arm` GitHub Runner. As such, we change
    the timeouts for arm64 in `codex-rs/linux-sandbox/tests/landlock.rs`.
    
    Though in solving this problem, I decided I needed a turnkey solution
    for testing the Linux build(s) from my Mac laptop, so this PR introduces
    `.devcontainer/Dockerfile` and `.devcontainer/devcontainer.json` to
    facilitate this. Detailed instructions are in `.devcontainer/README.md`.
    
    We will update `dotslash-config.json` and other release-related scripts
    in a follow-up PR.
  • feat: add support for login with ChatGPT (#1212)
    This does not implement the full Login with ChatGPT experience, but it
    should unblock people.
    
    **What works**
    
    * The `codex` multitool now has a `login` subcommand, so you can run
    `codex login`, which should write `CODEX_HOME/auth.json` if you complete
    the flow successfully. The TUI will now read the `OPENAI_API_KEY` from
    `auth.json`.
    * The TUI should refresh the token if it has expired and the necessary
    information is in `auth.json`.
    * There is a `LoginScreen` in the TUI that tells you to run `codex
    login` if both (1) your model provider expects to use `OPENAI_API_KEY`
    as its env var, and (2) `OPENAI_API_KEY` is not set.
    
    **What does not work**
    
    * The `LoginScreen` does not support the login flow from within the TUI.
    Instead, it tells you to quit, run `codex login`, and then run `codex`
    again.
    * `codex exec` does read from `auth.json` yet, nor does it direct the
    user to go through the login flow if `OPENAI_API_KEY` is not be found.
    * The `maybeRedeemCredits()` function from `get-api-key.tsx` has not
    been ported from TypeScript to `login_with_chatgpt.py` yet:
    
    
    https://github.com/openai/codex/blob/a67a67f3258fc21e147b6786a143fe3e15e6d5ba/codex-cli/src/utils/get-api-key.tsx#L84-L89
    
    **Implementation**
    
    Currently, the OAuth flow requires running a local webserver on
    `127.0.0.1:1455`. It seemed wasteful to incur the additional binary cost
    of a webserver dependency in the Rust CLI just to support login, so
    instead we implement this logic in Python, as Python has a `http.server`
    module as part of its standard library. Specifically, we bundle the
    contents of a single Python file as a string in the Rust CLI and then
    use it to spawn a subprocess as `python3 -c
    {{SOURCE_FOR_PYTHON_SERVER}}`.
    
    As such, the most significant files in this PR are:
    
    ```
    codex-rs/login/src/login_with_chatgpt.py
    codex-rs/login/src/lib.rs
    ```
    
    Now that the CLI may load `OPENAI_API_KEY` from the environment _or_
    `CODEX_HOME/auth.json`, we need a new abstraction for reading/writing
    this variable, so we introduce:
    
    ```
    codex-rs/core/src/openai_api_key.rs
    ```
    
    Note that `std::env::set_var()` is [rightfully] `unsafe` in Rust 2024,
    so we use a LazyLock<RwLock<Option<String>>> to store `OPENAI_API_KEY`
    so it is read in a thread-safe manner.
    
    Ultimately, it should be possible to go through the entire login flow
    from the TUI. This PR introduces a placeholder `LoginScreen` UI for that
    right now, though the new `codex login` subcommand introduced in this PR
    should be a viable workaround until the UI is ready.
    
    **Testing**
    
    Because the login flow is currently implemented in a standalone Python
    file, you can test it without building any Rust code as follows:
    
    ```
    rm -rf /tmp/codex_home && mkdir /tmp/codex_home
    CODEX_HOME=/tmp/codex_home python3 codex-rs/login/src/login_with_chatgpt.py
    ```
    
    For reference:
    
    * the original TypeScript implementation was introduced in
    https://github.com/openai/codex/pull/963
    * support for redeeming credits was later added in
    https://github.com/openai/codex/pull/974
  • codex-rs: make tool calls prettier (#1211)
    This PR overhauls how active tool calls and completed tool calls are
    displayed:
    
    1. More use of colour to indicate success/failure and distinguish
    between components like tool name+arguments
    2. Previously, the entire `CallToolResult` was serialized to JSON and
    pretty-printed. Now, we extract each individual `CallToolResultContent`
    and print those
    1. The previous solution was wasting space by unnecessarily showing
    details of the `CallToolResult` struct to users, without formatting the
    actual tool call results nicely
    2. We're now able to show users more information from tool results in
    less space, with nicer formatting when tools return JSON results
    
    ### Before:
    
    <img width="1251" alt="Screenshot 2025-06-03 at 11 24 26"
    src="https://github.com/user-attachments/assets/5a58f222-219c-4c53-ace7-d887194e30cf"
    />
    
    ### After:
    
    <img width="1265" alt="image"
    src="https://github.com/user-attachments/assets/99fe54d0-9ebe-406a-855b-7aa529b91274"
    />
    
    ## Future Work
    
    1. Integrate image tool result handling better. We should be able to
    display images even if they're not the first `CallToolResultContent`
    2. Users should have some way to view the full version of truncated tool
    results
    3. It would be nice to add some left padding for tool results, make it
    more clear that they are results. This is doable, just a little fiddly
    due to the way `first_visible_line` scrolling works
    4. There's almost certainly a better way to format JSON than "all on 1
    line with spaces to make Ratatui wrapping work". But I think that works
    OK for now.
  • fix: always send full instructions when using the Responses API (#1207)
    This fixes a longstanding error in the Rust CLI where `codex.rs`
    contained an errant `is_first_turn` check that would exclude the user
    instructions for subsequent "turns" of a conversation when using the
    responses API (i.e., when `previous_response_id` existed).
    
    While here, renames `Prompt.instructions` to `Prompt.user_instructions`
    since we now have quite a few levels of instructions floating around.
    Also removed an unnecessary use of `clone()` in
    `Prompt.get_full_instructions()`.
  • fix: provide tolerance for apply_patch tool (#993)
    As explained in detail in the doc comment for `ParseMode::Lenient`, we
    have observed that GPT-4.1 does not always generate a valid invocation
    of `apply_patch`. Fortunately, the error is predictable, so we introduce
    some new logic to the `codex-apply-patch` crate to recover from this
    error.
    
    Because we would like to avoid this becoming a de facto standard (as it
    would be incompatible if `apply_patch` were provided as an actual
    executable, unless we also introduced the lenient behavior in the
    executable, as well), we require passing `ParseMode::Lenient` to
    `parse_patch_text()` to make it clear that the caller is opting into
    supporting this special case.
    
    Note the analogous change to the TypeScript CLI was
    https://github.com/openai/codex/pull/930. In addition to changing the
    accepted input to `apply_patch`, it also introduced additional
    instructions for the model, which we include in this PR.
    
    Note that `apply-patch` does not depend on either `regex` or
    `regex-lite`, so some of the checks are slightly more verbose to avoid
    introducing this dependency.
    
    That said, this PR does not leverage the existing
    `extract_heredoc_body_from_apply_patch_command()`, which depends on
    `tree-sitter` and `tree-sitter-bash`:
    
    
    https://github.com/openai/codex/blob/5a5aa899143f9b9ef606692c401b010368b15bdb/codex-rs/apply-patch/src/lib.rs#L191-L246
    
    though perhaps it should.
  • chore: replace regex with regex-lite, where appropriate (#1200)
    As explained on https://crates.io/crates/regex-lite, `regex-lite` is a
    lighter alternative to `regex` and seems to be sufficient for our
    purposes.
  • feat: make reasoning effort/summaries configurable (#1199)
    Previous to this PR, we always set `reasoning` when making a request
    using the Responses API:
    
    
    https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
    
    Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
    would fail with:
    
    ```shell
    "Unsupported parameter: 'reasoning.effort' is not supported with this model."
    ```
    
    We take a cue from the TypeScript CLI, which does a check on the model
    name:
    
    
    https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
    
    This PR does a similar check, though also adds support for the following
    config options:
    
    ```
    model_reasoning_effort = "low" | "medium" | "high" | "none"
    model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
    ```
    
    This way, if you have a model whose name happens to start with `"o"` (or
    `"codex"`?), you can set these to `"none"` to explicitly disable
    reasoning, if necessary. (That said, it seems unlikely anyone would use
    the Responses API with non-OpenAI models, but we provide an escape
    hatch, anyway.)
    
    This PR also updates both the TUI and `codex exec` to show `reasoning
    effort` and `reasoning summaries` in the header.
  • fix: chat completions API now also passes tools along (#1167)
    Prior to this PR, there were two big misses in `chat_completions.rs`:
    
    1. The loop in `stream_chat_completions()` was only including items of
    type `ResponseItem::Message` when building up the `"messages"` JSON for
    the `POST` request to the `chat/completions` endpoint. This fixes things
    by ensuring other variants (`FunctionCall`, `LocalShellCall`, and
    `FunctionCallOutput`) are included, as well.
    2. In `process_chat_sse()`, we were not recording tool calls and were
    only emitting items of type
    `ResponseEvent::OutputItemDone(ResponseItem::Message)` to the stream.
    Now we introduce `FunctionCallState`, which is used to accumulate the
    `delta`s of type `tool_calls`, so we can ultimately emit a
    `ResponseItem::FunctionCall`, when appropriate.
    
    While function calling now appears to work for chat completions with my
    local testing, I believe that there are still edge cases that are not
    covered and that this codepath would benefit from a battery of
    integration tests. (As part of that further cleanup, we should also work
    to support streaming responses in the UI.)
    
    The other important part of this PR is some cleanup in
    `core/src/codex.rs`. In particular, it was hard to reason about how
    `run_task()` was building up the list of messages to include in a
    request across the various cases:
    
    - Responses API
    - Chat Completions API
    - Responses API used in concert with ZDR
    
    I like to think things are a bit cleaner now where:
    
    - `zdr_transcript` (if present) contains all messages in the history of
    the conversation, which includes function call outputs that have not
    been sent back to the model yet
    - `pending_input` includes any messages the user has submitted while the
    turn is in flight that need to be injected as part of the next `POST` to
    the model
    - `input_for_next_turn` includes the tool call outputs that have not
    been sent back to the model yet