Commit Graph

252 Commits

  • fix: read version from package.json instead of modifying session.ts (#753)
    I am working to simplify the build process. As a first step, update
    `session.ts` so it reads the `version` from `package.json` at runtime so
    we no longer have to modify it during the build process. I want to get
    to a place where the build looks like:
    
    ```
    cd codex-cli
    pnpm i
    pnpm build
    RELEASE_DIR=$(mktemp -d)
    cp -r bin "$RELEASE_DIR/bin"
    cp -r dist "$RELEASE_DIR/dist"
    cp -r src "$RELEASE_DIR/src" # important if we want sourcemaps to continue to work
    cp ../README.md "$RELEASE_DIR"
    VERSION=$(printf '0.1.%d' $(date +%y%m%d%H%M))
    jq --arg version "$VERSION" '.version = $version' package.json > "$RELEASE_DIR/package.json"
    ```
    
    Then the contents of `$RELEASE_DIR` should be good to `npm publish`, no?
  • chore: remove the REPL crate/subcommand (#754)
    @oai-ragona and I discussed it, and we feel the REPL crate has served
    its purpose, so we're going to delete the code and future archaeologists
    can find it in Git history.
  • fix: remove expected dot after v in rust-v tag name (#742)
    I think this extra dot was not intentional, but I'm not sure. Certainly
    this comment suggests it should not be there:
    
    
    https://github.com/openai/codex/blob/85999d72770832e2b1b457401c6c68d86e08344b/.github/workflows/rust-release.yml#L4
  • chore: fix errors in .github/workflows/rust-release.yml and prep 0.0.2504292006 release (#745)
    Apparently I made two key mistakes in
    https://github.com/openai/codex/pull/740 (fixed in this PR):
    
    * I forgot to redefine `$dest` in the `Stage Linux-only artifacts` step
    * I did not define the `if` check correctly in the `Stage Linux-only
    artifacts` step
    
    This fixes both of those issues and bumps the workspace version to
    `0.0.2504292006` in preparation for another release attempt.
  • fix: primary output of the codex-cli crate is named codex, not codex-cli (#743)
    I just got a bunch of failures in the release workflow:
    
    https://github.com/openai/codex/actions/runs/14745492805/job/41391926707
    
    along the lines of:
    
    ```
    cp: cannot stat 'target/aarch64-unknown-linux-gnu/release/codex-cli': No such file or directory
    ```
  • feat: codex-linux-sandbox standalone executable (#740)
    This introduces a standalone executable that run the equivalent of the
    `codex debug landlock` subcommand and updates `rust-release.yml` to
    include it in the release.
    
    The idea is that we will include this small binary with the TypeScript
    CLI to provide support for Linux sandboxing.
  • [codex-rs] Add rust-release action (#671)
    Taking a pass at building artifacts per platform so we can consider
    different distribution strategies that don't require users to install
    the full `cargo` toolchain.
    
    Right now this grabs just the `codex-repl` and `codex-tui` bins for 5
    different targets and bundles them into a draft release. I think a
    clearly marked pre-release set of artifacts will unblock the next step
    of testing.
  • fix: overhaul SandboxPolicy and config loading in Rust (#732)
    Previous to this PR, `SandboxPolicy` was a bit difficult to work with:
    
    
    https://github.com/openai/codex/blob/237f8a11e11fdcc793a09e787e48215676d9b95b/codex-rs/core/src/protocol.rs#L98-L108
    
    Specifically:
    
    * It was an `enum` and therefore options were mutually exclusive as
    opposed to additive.
    * It defined things in terms of what the agent _could not_ do as opposed
    to what they _could_ do. This made things hard to support because we
    would prefer to build up a sandbox config by starting with something
    extremely restrictive and only granting permissions for things the user
    as explicitly allowed.
    
    This PR changes things substantially by redefining the policy in terms
    of two concepts:
    
    * A `SandboxPermission` enum that defines permissions that can be
    granted to the agent/sandbox.
    * A `SandboxPolicy` that internally stores a `Vec<SandboxPermission>`,
    but externally exposes a simpler API that can be used to configure
    Seatbelt/Landlock.
    
    Previous to this PR, we supported a `--sandbox` flag that effectively
    mapped to an enum value in `SandboxPolicy`. Though now that
    `SandboxPolicy` is a wrapper around `Vec<SandboxPermission>`, the single
    `--sandbox` flag no longer makes sense. While I could have turned it
    into a flag that the user can specify multiple times, I think the
    current values to use with such a flag are long and potentially messy,
    so for the moment, I have dropped support for `--sandbox` altogether and
    we can bring it back once we have figured out the naming thing.
    
    Since `--sandbox` is gone, users now have to specify `--full-auto` to
    get a sandbox that allows writes in `cwd`. Admittedly, there is no clean
    way to specify the equivalent of `--full-auto` in your `config.toml`
    right now, so we will have to revisit that, as well.
    
    Because `Config` presents a `SandboxPolicy` field and `SandboxPolicy`
    changed considerably, I had to overhaul how config loading works, as
    well. There are now two distinct concepts, `ConfigToml` and `Config`:
    
    * `ConfigToml` is the deserialization of `~/.codex/config.toml`. As one
    might expect, every field is `Optional` and it is `#[derive(Deserialize,
    Default)]`. Consistent use of `Optional` makes it clear what the user
    has specified explicitly.
    * `Config` is the "normalized config" and is produced by merging
    `ConfigToml` with `ConfigOverrides`. Where `ConfigToml` contains a raw
    `Option<Vec<SandboxPermission>>`, `Config` presents only the final
    `SandboxPolicy`.
    
    The changes to `core/src/exec.rs` and `core/src/linux.rs` merit extra
    special attention to ensure we are faithfully mapping the
    `SandboxPolicy` to the Seatbelt and Landlock configs, respectively.
    
    Also, take note that `core/src/seatbelt_readonly_policy.sbpl` has been
    renamed to `codex-rs/core/src/seatbelt_base_policy.sbpl` and that
    `(allow file-read*)` has been removed from the `.sbpl` file as now this
    is added to the policy in `core/src/exec.rs` when
    `sandbox_policy.has_full_disk_read_access()` is `true`.
  • feat: add common package registries domains to allowed-domains list (#414)
    feat: add common package registries domains to allowed-domains list
  • Fixes issue #726 by adding config to configToSave object (#728)
    The saveConfig() function only includes a hardcoded subset of properties
    when writing the config file. Any property not explicitly listed (like
    disableResponseStorage) will be dropped.
    I have added `disableResponseStorage` to the `configToSave` object as
    the immediate fix.
    
    [Linking Issue this fixes.](https://github.com/openai/codex/issues/726)
  • feat: add --reasoning CLI flag (#314)
    This PR adds a new CLI flag: `--reasoning`, which allows users to
    customize the reasoning effort level (`low`, `medium`, or `high`) used
    by OpenAI's `o` models.
    By introducing the `--reasoning` flag, users gain more flexibility when
    working with the models. It enables optimization for either speed or
    depth of reasoning, depending on specific use cases.
    This PR resolves #107
    
    - **Flag**: `--reasoning`
    - **Accepted Values**: `low`, `medium`, `high`
    - **Default Behavior**: If not specified, the model uses the default
    reasoning level.
    
    ## Example Usage
    
    ```bash
    codex --reasoning=low "Write a simple function to calculate factorial"
    
    ---------
    
    Co-authored-by: Fouad Matin <169186268+fouad-openai@users.noreply.github.com>
    Co-authored-by: yashrwealthy <yash.rastogi@wealthy.in>
    Co-authored-by: Thibault Sottiaux <tibo@openai.com>
  • fix: eliminate runtime dependency on patch(1) for apply_patch (#718)
    When processing an `apply_patch` tool call, we were already computing
    the new file content in order to compute the unified diff. Before this
    PR, we were shelling out to `patch(1)` to apply the unified diff once
    the user accepted the change, but this updates the code to just retain
    the new file content and use it to write the file when the user accepts.
    This simplifies deployment because it no longer assumes `patch(1)` is on
    the host.
    
    Note this change is internal to the Codex agent and does not affect
    `protocol.rs`.
  • feat: lower default retry wait time and increase number of tries (#720)
    In total we now guarantee that we will wait for at least 60s before
    giving up.
    
    ---------
    
    Signed-off-by: Thibault Sottiaux <tibo@openai.com>
  • feat: add debug landlock subcommand comparable to debug seatbelt (#715)
    This PR adds a `debug landlock` subcommand to the Codex CLI for testing
    how Codex would execute a command using the specified sandbox policy.
    
    Built and ran this code in the `rust:latest` Docker container. In the
    container, hitting the network with vanilla `curl` succeeds:
    
    ```
    $ curl google.com
    <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
    <TITLE>301 Moved</TITLE></HEAD><BODY>
    <H1>301 Moved</H1>
    The document has moved
    <A HREF="http://www.google.com/">here</A>.
    </BODY></HTML>
    ```
    
    whereas this fails, as expected:
    
    ```
    $ cargo run -- debug landlock -s network-restricted -- curl google.com
    curl: (6) getaddrinfo() thread failed to start
    ```
  • feat: make it possible to set disable_response_storage = true in config.toml (#714)
    https://github.com/openai/codex/pull/642 introduced support for the
    `--disable-response-storage` flag, but if you are a ZDR customer, it is
    tedious to set this every time, so this PR makes it possible to set this
    once in `config.toml` and be done with it.
    
    Incidentally, this tidies things up such that now `init_codex()` takes
    only one parameter: `Config`.
  • fix: make the TUI the default/"interactive" CLI in Rust (#711)
    Originally, the `interactive` crate was going to be a placeholder for
    building out a UX that was comparable to that of the existing TypeScript
    CLI. Though after researching how Ratatui works, that seems difficult to
    do because it is designed around the idea that it will redraw the full
    screen buffer each time (and so any scrolling should be "internal" to
    your Ratatui app) whereas the TypeScript CLI expects to render the full
    history of the conversation every time(*) (which is why you can use your
    terminal scrollbar to scroll it).
    
    While it is possible to use Ratatui in a way that acts more like what
    the TypeScript CLI is doing, it is awkward and seemingly results in
    tedious code, so I think we should abandon that approach. As such, this
    PR deletes the `interactive/` folder and the code that depended on it.
    
    Further, since we added support for mousewheel scrolling in the TUI in
    https://github.com/openai/codex/pull/641, it certainly feels much better
    and the need for scroll support via the terminal scrollbar is greatly
    diminished. This is now a more appropriate default UX for the
    "multitool" CLI.
    
    (*) Incidentally, I haven't verified this, but I think this results in
    O(N^2) work in rendering, which seems potentially problematic for long
    conversations.
  • fix: tighten up check for /usr/bin/sandbox-exec (#710)
    * In both TypeScript and Rust, we now invoke `/usr/bin/sandbox-exec`
    explicitly rather than whatever `sandbox-exec` happens to be on the
    `PATH`.
    * Changed `isSandboxExecAvailable` to use `access()` rather than
    `command -v` so that:
      *  We only do the check once over the lifetime of the Codex process.
      * The check is specific to `/usr/bin/sandbox-exec`.
    * We now do a syscall rather than incur the overhead of spawning a
    process, dealing with timeouts, etc.
    
    I think there is still room for improvement here where we should move
    the `isSandboxExecAvailable` check earlier in the CLI, ideally right
    after we do arg parsing to verify that we can provide the Seatbelt
    sandbox if that is what the user has requested.
  • fix: increase timeout of test_writable_root (#713)
    Although we made some promising fixes in
    https://github.com/openai/codex/pull/662, we are still seeing some
    flakiness in `test_writable_root()`. If this continues to flake with the
    more generous timeout, we should try something other than simply
    increasing the timeout.
  • fix: drop d as keyboard shortcut for scrolling in the TUI (#704)
    The existing `b` and `space` are sufficient and `d` and `u` default to
    half-page scrolling in `less`, so the way we supported `d` and `u`
    wasn't faithful to that, anyway:
    
    https://man7.org/linux/man-pages/man1/less.1.html
    
    If we decide to bring `d` and `u` back, they should probably match
    `less`?
  • feat: load defaults into Config and introduce ConfigOverrides (#677)
    This changes how instantiating `Config` works and also adds
    `approval_policy` and `sandbox_policy` as fields. The idea is:
    
    * All fields of `Config` have appropriate default values.
    * `Config` is initially loaded from `~/.codex/config.toml`, so values in
    `config.toml` will override those defaults.
    * Clients must instantiate `Config` via
    `Config::load_with_overrides(ConfigOverrides)` where `ConfigOverrides`
    has optional overrides that are expected to be settable based on CLI
    flags.
    
    The `Config` should be defined early in the program and then passed
    down. Now functions like `init_codex()` take fewer individual parameters
    because they can just take a `Config`.
    
    Also, `Config::load()` used to fail silently if `~/.codex/config.toml`
    had a parse error and fell back to the default config. This seemed
    really bad because it wasn't clear why the values in my `config.toml`
    weren't getting picked up. I changed things so that
    `load_with_overrides()` returns `Result<Config>` and verified that the
    various CLIs print a reasonable error if `config.toml` is malformed.
    
    Finally, I also updated the TUI to show which **sandbox** value is being
    used, as we do for other key values like **model** and **approval**.
    This was also a reminder that the various values of `--sandbox` are
    honored on Linux but not macOS today, so I added some TODOs about fixing
    that.
  • fix: check if sandbox-exec is available (#696)
    - Introduce `isSandboxExecAvailable()` helper and tidy import ordering
    in `handle-exec-command.ts`.
    - Add runtime check for the `sandbox-exec` binary on macOS; fall back to
    `SandboxType.NONE` with a warning if it’s missing, preventing crashes.
    
    ---------
    
    Signed-off-by: Thibault Sottiaux <tibo@openai.com>
    Co-authored-by: Fouad Matin <fouad@openai.com>
  • feat: user config api key (#569)
    Adds support for reading OPENAI_API_KEY (and other variables) from a
    user‑wide dotenv file (~/.codex.config). Precedence order is now:
      1. explicit environment variable
      2. project‑local .env (loaded earlier)
      3. ~/.codex.config
    
    Also adds a regression test that ensures the multiline editor correctly
    handles cases where printable text and the CSI‑u Shift+Enter sequence
    arrive in the same input chunk.
    
    House‑kept with Prettier; removed stray temp.json artifact.
  • fix: duplicate messages in quiet mode (#680)
    Addressing #600 and #664 (partially)
    
    ## Bug
    Codex was staging duplicate items in output running when the same
    response item appeared in both the streaming events. Specifically:
    
    1. Items would be staged once when received as a
    `response.output_item.done` event
    2. The same items would be staged again when included in the final
    `response.completed` payload
    
    This duplication would result in each message being sent several times
    in the quiet mode output.
    
    ## Changes
    - Added a Set (`alreadyStagedItemIds`) to track items that have already
    been staged
    - Modified the `stageItem` function to check if an item's ID is already
    in this set before staging it
    - Added a regression test (`agent-dedupe-items.test.ts`) that verifies
    items with the same ID are only staged once
    
    ## Testing
    Like other tests, the included test creates a mock OpenAI stream that
    emits the same message twice (once as an incremental event and once in
    the final response) and verifies the item is only passed to `onItem`
    once.
  • fix: write logs to ~/.codex/log instead of /tmp (#669)
    Previously, the Rust TUI was writing log files to `/tmp`, which is
    world-readable and not available on Windows, so that isn't great.
    
    This PR tries to clean things up by adding a function that provides the
    path to the "Codex config dir," e.g., `~/.codex` (though I suppose we
    could support `$CODEX_HOME` to override this?) and then defines other
    paths in terms of the result of `codex_dir()`.
    
    For example, `log_dir()` returns the folder where log files should be
    written which is defined in terms of `codex_dir()`. I updated the TUI to
    use this function. On UNIX, we even go so far as to `chmod 600` the log
    file by default, though as noted in a comment, it's a bit tedious to do
    the equivalent on Windows, so we just let that go for now.
    
    This also changes the default logging level to `info` for `codex_core`
    and `codex_tui` when `RUST_LOG` is not specified. I'm not really sure if
    we should use a more verbose default (it may be helpful when debugging
    user issues), though if so, we should probably also set up log rotation?
  • bump(version): 0.1.2504251709 (#660)
    ## `0.1.2504251709`
    
    ### 🚀 Features
    
    - Add openai model info configuration (#551)
    - Added provider to run quiet mode function (#571)
    - Create parent directories when creating new files (#552)
    - Print bug report URL in terminal instead of opening browser (#510)
    (#528)
    - Add support for custom provider configuration in the user config
    (#537)
    - Add support for OpenAI-Organization and OpenAI-Project headers (#626)
    - Add specific instructions for creating API keys in error msg (#581)
    - Enhance toCodePoints to prevent potential unicode 14 errors (#615)
    - More native keyboard navigation in multiline editor (#655)
    - Display error on selection of invalid model (#594)
    
    ### 🪲 Bug Fixes
    
    - Model selection (#643)
    - Nits in apply patch (#640)
    - Input keyboard shortcuts (#676)
    - `apply_patch` unicode characters (#625)
    - Don't clear turn input before retries (#611)
    - More loosely match context for apply_patch (#610)
    - Update bug report template - there is no --revision flag (#614)
    - Remove outdated copy of text input and external editor feature (#670)
    - Remove unreachable "disableResponseStorage" logic flow introduced in
    #543 (#573)
    - Non-openai mode - fix for gemini content: null, fix 429 to throw
    before stream (#563)
    - Only allow going up in history when not already in history if input is
    empty (#654)
    - Do not grant "node" user sudo access when using run_in_container.sh
    (#627)
    - Update scripts/build_container.sh to use pnpm instead of npm (#631)
    - Update lint-staged config to use pnpm --filter (#582)
    - Non-openai mode - don't default temp and top_p (#572)
    - Fix error catching when checking for updates (#597)
    - Close stdin when running an exec tool call (#636)
  • fix: input keyboard shortcuts (#676)
    Fixes keyboard shortcuts:
    - ctrl+a/e
    - opt+arrow keys
  • ci: build Rust on Windows as part of CI (#665)
    While we aren't ready to provide Windows binaries of Codex CLI, it seems
    like a good idea to ensure we guard platform-specific code
    appropriately.
  • fix: small fixes so Codex compiles on Windows (#673)
    Small fixes required:
    
    * `ExitStatusExt` differs because UNIX expects exit code to be `i32`
    whereas Windows does `u32`
    * Marking a file "executable only by owner" is a bit more involved on
    Windows. We just do something approximate for now (and add a TODO) to
    get things compiling.
    
    I created this PR on my personal Windows machine and `cargo test` and
    `cargo clippy` succeed. Once this is in, I'll rebase
    https://github.com/openai/codex/pull/665 on top so Windows stays fixed!
  • fix: remove dependency on expanduser crate (#667)
    In putting up https://github.com/openai/codex/pull/665, I discovered
    that the `expanduser` crate does not compile on Windows. Looking into
    it, we do not seem to need it because we were only using it with a value
    that was passed in via a command-line flag, so the shell expands `~` for
    us before we see it, anyway. (I changed the type in `Cli` from `String`
    to `PathBuf`, to boot.)
    
    If we do need this sort of functionality in the future,
    https://docs.rs/shellexpand/latest/shellexpand/fn.tilde.html seems
    promising.
  • fix: flipped the sense of Prompt.store in #642 (#663)
    I got the sense of this wrong in
    https://github.com/openai/codex/pull/642. In that PR, I made
    `--disable-response-storage` work, but broke the default case.
    
    With this fix, both cases work and I think the code is a bit cleaner.
  • [codex-rs] Improve linux sandbox timeouts (#662)
    * Fixes flaking rust unit test
    * Adds explicit sandbox exec timeout handling
  • [codex-rs] CI performance for rust (#639)
    * Refactors the rust-ci into a matrix build
    * Adds directory caching for the build artifacts
    * Adds workflow dispatch for manual testing
  • feat: add ZDR support to Rust implementation (#642)
    This adds support for the `--disable-response-storage` flag across our
    multiple Rust CLIs to support customers who have opted into Zero-Data
    Retention (ZDR). The analogous changes to the TypeScript CLI were:
    
    * https://github.com/openai/codex/pull/481
    * https://github.com/openai/codex/pull/543
    
    For a client using ZDR, `previous_response_id` will never be available,
    so the `input` field of an API request must include the full transcript
    of the conversation thus far. As such, this PR changes the type of
    `Prompt.input` from `Vec<ResponseInputItem>` to `Vec<ResponseItem>`.
    
    Practically speaking, `ResponseItem` was effectively a "superset" of
    `ResponseInputItem` already. The main difference for us is that
    `ResponseItem` includes the `FunctionCall` variant that we have to
    include as part of the conversation history in the ZDR case.
    
    Another key change in this PR is modifying `try_run_turn()` so that it
    returns the `Vec<ResponseItem>` for the turn in addition to the
    `Vec<ResponseInputItem>` produced by `try_run_turn()`. This is because
    the caller of `run_turn()` needs to record the `Vec<ResponseItem>` when
    ZDR is enabled.
    
    To that end, this PR introduces `ZdrTranscript` (and adds
    `zdr_transcript: Option<ZdrTranscript>` to `struct State` in `codex.rs`)
    to take responsibility for maintaining the conversation transcript in
    the ZDR case.
  • feat(tui-rs): add support for mousewheel scrolling (#641)
    It is intuitive to try to scroll the conversation history using the
    mouse in the TUI, but prior to this change, we only supported scrolling
    via keyboard events.
    
    This PR enables mouse capture upon initialization (and disables it on
    exit) such that we get `ScrollUp` and `ScrollDown` events in
    `codex-rs/tui/src/app.rs`. I initially mapped each event to scrolling by
    one line, but that felt sluggish. I decided to introduce
    `ScrollEventHelper` so we could debounce scroll events and measure the
    number of scroll events in a 100ms window to determine the "magnitude"
    of the scroll event. I put in a basic heuristic to start, but perhaps
    someone more motivated can play with it over time.
    
    `ScrollEventHelper` takes care of handling the atomic fields and thread
    management to ensure an `AppEvent::Scroll` event is pumped back through
    the event loop at the appropriate time with the accumulated delta.
  • [codex-rs] Reliability pass on networking (#658)
    We currently see a behavior that looks like this:
    ```
    2025-04-25T16:52:24.552789Z  WARN codex_core::codex: stream disconnected - retrying turn (1/10 in 232ms)...
    codex> event: BackgroundEvent { message: "stream error: stream disconnected before completion: Transport error: error decoding response body; retrying 1/10 in 232ms…" }
    2025-04-25T16:52:54.789885Z  WARN codex_core::codex: stream disconnected - retrying turn (2/10 in 418ms)...
    codex> event: BackgroundEvent { message: "stream error: stream disconnected before completion: Transport error: error decoding response body; retrying 2/10 in 418ms…" }
    ```
    
    This PR contains a few different fixes that attempt to resolve/improve
    this:
    1. **Remove overall client timeout.** I think
    [this](https://github.com/openai/codex/pull/658/files#diff-c39945d3c42f29b506ff54b7fa2be0795b06d7ad97f1bf33956f60e3c6f19c19L173)
    is perhaps the big fix -- it looks to me like this was actually timing
    out even if events were still coming through, and that was causing a
    disconnect right in the middle of a healthy stream.
    2. **Cap response sizes.** We were frequently sending MUCH larger
    responses than the upstream typescript `codex`, and that was definitely
    not helping. [Fix
    here](https://github.com/openai/codex/pull/658/files#diff-d792bef59aa3ee8cb0cbad8b176dbfefe451c227ac89919da7c3e536a9d6cdc0R21-R26)
    for that one.
    3. **Much higher idle timeout.** Our idle timeout value was much lower
    than typescript.
    4. **Sub-linear backoff.** We were much too aggressively backing off,
    [this](https://github.com/openai/codex/pull/658/files#diff-5d5959b95c6239e6188516da5c6b7eb78154cd9cfedfb9f753d30a7b6d6b8b06R30-R33)
    makes it sub-exponential but maintains the jitter and such.
    
    I was seeing that `stream error: stream disconnected` behavior
    constantly, and anecdotally I can no longer reproduce. It feels much
    snappier.
  • perf: optimize token streaming with balanced approach (#635)
    - Replace setTimeout(10ms) with queueMicrotask for immediate processing
    - Add minimal 3ms setTimeout for rendering to maintain readable UX
    - Reduces per-token delay while preserving streaming experience
    - Add performance test to verify optimization works correctly
    
    ---------
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Co-authored-by: Thibault Sottiaux <tibo@openai.com>
  • feat: Add support for OpenAI-Organization and OpenAI-Project headers (#626)
    Added support for OpenAI-Organization and OpenAI-Project headers for
    OpenAI API calls.
    
    This is for #74