Commit Graph

17 Commits

  • use a central animation loop (#2268)
    instead of each shimmer needing to have its own animation thread, have
    render_ref schedule a new frame if it wants one and coalesce to the
    earliest next frame. this also makes the animations
    frame-timing-independent, based on start time instead of frame count.
  • remove "status text" in bottom line (#2279)
    this used to hold the most recent log line, but it was kinda broken and
    not that useful.
  • Re-add markdown streaming (#2029)
    Wait for newlines, then render markdown on a line by line basis. Word wrap it for the current terminal size and then spit it out line by line into the UI. Also adds tests and fixes some UI regressions.
  • Streaming markdown (#1920)
    We wait until we have an entire newline, then format it with markdown and stream in to the UI. This reduces time to first token but is the right thing to do with our current rendering model IMO. Also lets us add word wrapping!
  • Migrate GitWarning to OnboardingScreen (#1915)
    This paves the way to do per-directory approval settings
    (https://github.com/openai/codex/pull/1912).
    
    This also lets us pass in a Config/ChatWidgetArgs into onboarding which
    can then mutate it and emit the ChatWidgetArgs it wants at the end which
    may be modified by the said approval settings.
    
    <img width="1180" height="428" alt="CleanShot 2025-08-06 at 19 30 55"
    src="https://github.com/user-attachments/assets/4dcfda42-0f5e-4b6d-a16d-2597109cc31c"
    />
  • First pass at a TUI onboarding (#1876)
    This sets up the scaffolding and basic flow for a TUI onboarding
    experience. It covers sign in with ChatGPT, env auth, as well as some
    safety guidance.
    
    Next up:
    1. Replace the git warning screen
    2. Use this to configure default approval/sandbox modes
    
    
    Note the shimmer flashes are from me slicing the video, not jank.
    
    https://github.com/user-attachments/assets/0fbe3479-fdde-41f3-87fb-a7a83ab895b8
  • remove conversation history widget (#1727)
    this widget is no longer used.
  • Easily Selectable History (#1672)
    This update replaces the previous ratatui history widget with an
    append-only log so that the terminal can handle text selection and
    scrolling. It also disables streaming responses, which we'll do our best
    to bring back in a later PR. It also adds a small summary of token use
    after the TUI exits.
  • Implement redraw debounce (#1599)
    ## Summary
    - debouce redraw events so repeated requests don't overwhelm the
    terminal
    - add `RequestRedraw` event and schedule redraws after 100ms
    
    ## Testing
    - `cargo clippy --tests`
    - `cargo test` *(fails: Sandbox Denied errors in landlock tests)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68792a65b8b483218ec90a8f68746cd8
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • Add paste summarization to Codex TUI (#1549)
    ## Summary
    - introduce `Paste` event to avoid per-character paste handling
    - collapse large pasted blocks to `[Pasted Content X lines]`
    - store the real text so submission still includes it
    - wire paste handling through `App`, `ChatWidget`, `BottomPane`, and
    `ChatComposer`
    
    ## Testing
    - `cargo test -p codex-tui`
    
    
    ------
    https://chatgpt.com/codex/tasks/task_i_6871e24abf80832184d1f3ca0c61a5ee
    
    
    https://github.com/user-attachments/assets/eda7412f-da30-4474-9f7c-96b49d48fbf8
  • 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: add support for commands in the Rust TUI (#935)
    Introduces support for slash commands like in the TypeScript CLI. We do
    not support the full set of commands yet, but the core abstraction is
    there now.
    
    In particular, we have a `SlashCommand` enum and due to thoughtful use
    of the [strum](https://crates.io/crates/strum) crate, it requires
    minimal boilerplate to add a new command to the list.
    
    The key new piece of UI is `CommandPopup`, though the keyboard events
    are still handled by `ChatComposer`. The behavior is roughly as follows:
    
    * if the first character in the composer is `/`, the command popup is
    displayed (if you really want to send a message to Codex that starts
    with a `/`, simply put a space before the `/`)
    * while the popup is displayed, up/down can be used to change the
    selection of the popup
    * if there is a selection, hitting tab completes the command, but does
    not send it
    * if there is a selection, hitting enter sends the command
    * if the prefix of the composer matches a command, the command will be
    visible in the popup so the user can see the description (commands could
    take arguments, so additional text may appear after the command name
    itself)
    
    
    https://github.com/user-attachments/assets/39c3e6ee-eeb7-4ef7-a911-466d8184975f
    
    Incidentally, Codex wrote almost all the code for this PR!
  • feat: support the chat completions API in the Rust CLI (#862)
    This is a substantial PR to add support for the chat completions API,
    which in turn makes it possible to use non-OpenAI model providers (just
    like in the TypeScript CLI):
    
    * It moves a number of structs from `client.rs` to `client_common.rs` so
    they can be shared.
    * It introduces support for the chat completions API in
    `chat_completions.rs`.
    * It updates `ModelProviderInfo` so that `env_key` is `Option<String>`
    instead of `String` (for e.g., ollama) and adds a `wire_api` field
    * It updates `client.rs` to choose between `stream_responses()` and
    `stream_chat_completions()` based on the `wire_api` for the
    `ModelProviderInfo`
    * It updates the `exec` and TUI CLIs to no longer fail if the
    `OPENAI_API_KEY` environment variable is not set
    * It updates the TUI so that `EventMsg::Error` is displayed more
    prominently when it occurs, particularly now that it is important to
    alert users to the `CodexErr::EnvVar` variant.
    * `CodexErr::EnvVar` was updated to include an optional `instructions`
    field so we can preserve the behavior where we direct users to
    https://platform.openai.com if `OPENAI_API_KEY` is not set.
    * Cleaned up the "welcome message" in the TUI to ensure the model
    provider is displayed.
    * Updated the docs in `codex-rs/README.md`.
    
    To exercise the chat completions API from OpenAI models, I added the
    following to my `config.toml`:
    
    ```toml
    model = "gpt-4o"
    model_provider = "openai-chat-completions"
    
    [model_providers.openai-chat-completions]
    name = "OpenAI using Chat Completions"
    base_url = "https://api.openai.com/v1"
    env_key = "OPENAI_API_KEY"
    wire_api = "chat"
    ```
    
    Though to test a non-OpenAI provider, I installed ollama with mistral
    locally on my Mac because ChatGPT said that would be a good match for my
    hardware:
    
    ```shell
    brew install ollama
    ollama serve
    ollama pull mistral
    ```
    
    Then I added the following to my `~/.codex/config.toml`:
    
    ```toml
    model = "mistral"
    model_provider = "ollama"
    ```
    
    Note this code could certainly use more test coverage, but I want to get
    this in so folks can start playing with it.
    
    For reference, I believe https://github.com/openai/codex/pull/247 was
    roughly the comparable PR on the TypeScript side.
  • 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.
  • feat: initial import of Rust implementation of Codex CLI in codex-rs/ (#629)
    As stated in `codex-rs/README.md`:
    
    Today, Codex CLI is written in TypeScript and requires Node.js 22+ to
    run it. For a number of users, this runtime requirement inhibits
    adoption: they would be better served by a standalone executable. As
    maintainers, we want Codex to run efficiently in a wide range of
    environments with minimal overhead. We also want to take advantage of
    operating system-specific APIs to provide better sandboxing, where
    possible.
    
    To that end, we are moving forward with a Rust implementation of Codex
    CLI contained in this folder, which has the following benefits:
    
    - The CLI compiles to small, standalone, platform-specific binaries.
    - Can make direct, native calls to
    [seccomp](https://man7.org/linux/man-pages/man2/seccomp.2.html) and
    [landlock](https://man7.org/linux/man-pages/man7/landlock.7.html) in
    order to support sandboxing on Linux.
    - No runtime garbage collection, resulting in lower memory consumption
    and better, more predictable performance.
    
    Currently, the Rust implementation is materially behind the TypeScript
    implementation in functionality, so continue to use the TypeScript
    implmentation for the time being. We will publish native executables via
    GitHub Releases as soon as we feel the Rust version is usable.