Commit Graph

502 Commits

  • feat(tui): show minutes/hours in thinking timer (#3220)
    What
      
    - Show compact elapsed time in the TUI status indicator: Xs, MmSSs,
    HhMMmSSs.
      - Add private helper fmt_elapsed_compact with a unit test.
      
      Why
      
    - Seconds‑only becomes hard to read during longer runs; minutes/hours
    improve clarity without extra noise.
      
      How
      
      - Implemented in codex-rs/tui/src/status_indicator_widget.rs only.
    - The helper is used when rendering the existing “Working/Thinking”
    timer.
    - No changes to codex-common::elapsed::format_duration or other crates.
      
      Scope/Impact
      
      - TUI‑only; no public API changes; minimal risk.
      - Snapshot tests should remain unchanged (most show “0s”).
      
      Before/After
      
    - Working (65s • Esc to interrupt) → Working (1m05s • Esc to interrupt)
      - Working (3723s • …) → Working (1h02m03s • …)
      
      Tests
      
      - Unit: fmt_elapsed_compact_formats_seconds_minutes_hours.
    - Local checks: cargo fmt --all, cargo clippy -p codex-tui -- -D
    warnings, cargo test -p codex-tui.
      
      Notes
      
    - Open to adjusting the exact format or moving the helper if maintainers
    prefer a shared location.
    
    Signed-off-by: Enrique Moreno Tent <enriquemorenotent@gmail.com>
  • hide resume until it's complete (#3218)
    Hide resume functionality until it's fully done.
  • Never store requests (#3212)
    When item ids are sent to Responses API it will load them from the
    database ignoring the provided values. This adds extra latency.
    
    Not having the mode to store requests also allows us to simplify the
    code.
    
    ## Breaking change
    
    The `disable_response_storage` configuration option is removed.
  • syntax-highlight bash lines (#3142)
    i'm not yet convinced i have the best heuristics for what to highlight,
    but this feels like a useful step towards something a bit easier to
    read, esp. when the model is producing large commands.
    
    <img width="669" height="589" alt="Screenshot 2025-09-03 at 8 21 56 PM"
    src="https://github.com/user-attachments/assets/b9cbcc43-80e8-4d41-93c8-daa74b84b331"
    />
    
    also a fairly significant refactor of our line wrapping logic.
  • refactor: remove AttachImage tui event (#3191)
    TuiEvent is supposed to be purely events that come from the "driver",
    i.e. events from the terminal. Everything app-specific should be an
    AppEvent. In this case, it didn't need to be an event at all.
  • tui: fix approval dialog for large commands (#3087)
    #### Summary
    - Emit a “Proposed Command” history cell when an ExecApprovalRequest
    arrives (parity with proposed patches).
    - Simplify the approval dialog: show only the reason/instructions; move
    the command preview into history.
    - Make approval/abort decision history concise:
      - Single line snippet; if multiline, show first line + " ...".
      - Truncate to 80 graphemes with ellipsis for very long commands.
    
    #### Details
    - History
    - Add `new_proposed_command` to render a header and indented command
    preview.
      - Use shared `prefix_lines` helper for first/subsequent line prefixes.
    - Approval UI
    - `UserApprovalWidget` no longer renders the command in the modal; shows
    optional `reason` text only.
      - Decision history renders an inline, dimmed snippet per rules above.
    - Tests (snapshot-based)
      - Proposed/decision flow for short command.
      - Proposed multi-line + aborted decision snippet with “ ...”.
      - Very long one-line command -> truncated snippet with “…”.
      - Updated existing exec approval snapshots and test reasons.
    
    <img width="1053" height="704" alt="Screenshot 2025-09-03 at 11 57
    35 AM"
    src="https://github.com/user-attachments/assets/9ed4c316-9daf-4ac1-80ff-7ae1f481dd10"
    />
    
    after approving:
    
    <img width="1053" height="704" alt="Screenshot 2025-09-03 at 11 58
    18 AM"
    src="https://github.com/user-attachments/assets/a44e243f-eb9d-42ea-87f4-171b3fb481e7"
    />
    
    rejection:
    
    <img width="1053" height="207" alt="Screenshot 2025-09-03 at 11 58
    45 AM"
    src="https://github.com/user-attachments/assets/a022664b-ae0e-4b70-a388-509208707934"
    />
    
    big command:
    
    
    https://github.com/user-attachments/assets/2dd976e5-799f-4af7-9682-a046e66cc494
  • Correctly calculate remaining context size (#3190)
    We had multiple issues with context size calculation:
    1. `initial_prompt_tokens` calculation based on cache size is not
    reliable, cache misses might set it to much higher value. For now
    hardcoded to a safer constant.
    2. Input context size for GPT-5 is 272k (that's where 33% came from).
    
    Fixes.
  • Pause status timer while modals are open (#3131)
    Summary:
    - pause the status timer while waiting on approval modals
    - expose deterministic pause/resume helpers to avoid sleep-based tests
    - simplify bottom pane timer handling now that the widget owns the clock
  • tui: pager pins scroll to bottom (#3167)
    when the pager is scrolled to the bottom of the buffer, keep it there.
    
    this should make transcript mode feel a bit more "alive". i've also seen
    some confusion about what transcript mode does/doesn't show that i think
    has been related to it not pinning scroll.
  • Use ⌥⇧⌃ glyphs for key hints on mac (#3143)
    #### Summary
    - render the edit queued message shortcut with the ⌥ modifier on macOS
    builds
    - add a helper for status indicator snapshot suffixes
    - record macOS-specific snapshots for the status indicator widget
  • fix: fix serde_as annotation and verify with test (#3170)
    I didn't do https://github.com/openai/codex/pull/3163 correctly the
    first time: now verified with a test.
  • [codex] improve handling of reasoning summary (#3138)
    <img width="1474" height="289" alt="Screenshot 2025-09-03 at 5 27 19 PM"
    src="https://github.com/user-attachments/assets/d6febcdd-fd9c-488c-9e82-348600b1f757"
    />
    
    Fallback to standard behavior when there is no summary in cot, and also
    added tests to codify this behavior.
  • tui: avoid panic when active exec cell area is zero height (#3133)
    #### Summary
    Avoid a potential panic when rendering the active execution cell when
    the allocated area has zero height.
    
    #### Changes
    - Guard rendering with `active_cell_area.height > 0` and presence of
    `active_exec_cell`.
    - Use `saturating_add(1)` for the Y offset to avoid overflow.
    - Render via `active_exec_cell.as_ref().unwrap().render_ref(...)` after
    the explicit `is_some` check.
  • TUI: Add session resume picker (--resume) and quick resume (--continue) (#3135)
    Adds a TUI resume flow with an interactive picker and quick resume.
    
    - CLI: 
      - --resume / -r: open picker to resume a prior session
      - --continue   / -l: resume the most recent session (no picker)
    - Behavior on resume: initial history is replayed, welcome banner
    hidden, and the first redraw is suppressed to avoid flicker.
    - Implementation:
    - New tui/src/resume_picker.rs (paginated listing via
    RolloutRecorder::list_conversations)
      - App::run accepts ResumeSelection; resumes from disk when requested
    - ChatWidget refactor with ChatWidgetInit and new_from_existing; replays
    initial messages
    - Tests: cover picker sorting/preview extraction and resumed-history
    rendering.
    - Docs: getting-started updated with flags and picker usage.
    
    
    
    https://github.com/user-attachments/assets/1bb6469b-e5d1-42f6-bec6-b1ae6debda3b
  • Dividing UserMsgs into categories to send it back to the tui (#3127)
    This PR does the following:
    
    - divides user msgs into 3 categories: plain, user instructions, and
    environment context
    - Centralizes adding user instructions and environment context to a
    degree
    - Improve the integration testing
    
    Building on top of #3123
    
    Specifically this
    [comment](https://github.com/openai/codex/pull/3123#discussion_r2319885089).
    We need to send the user message while ignoring the User Instructions
    and Environment Context we attach.
  • Replay EventMsgs from Response Items when resuming a session with history. (#3123)
    ### Overview
    
    This PR introduces the following changes:
    	1.	Adds a unified mechanism to convert ResponseItem into EventMsg.
    2. Ensures that when a session is initialized with initial history, a
    vector of EventMsg is sent along with the session configuration. This
    allows clients to re-render the UI accordingly.
    	3. 	Added integration testing
    
    ### Caveats
    
    This implementation does not send every EventMsg that was previously
    dispatched to clients. The excluded events fall into two categories:
    	•	“Arguably” rolled-out events
    Examples include tool calls and apply-patch calls. While these events
    are conceptually rolled out, we currently only roll out ResponseItems.
    These events are already being handled elsewhere and transformed into
    EventMsg before being sent.
    	•	Non-rolled-out events
    Certain events such as TurnDiff, Error, and TokenCount are not rolled
    out at all.
    
    ### Future Directions
    
    At present, resuming a session involves maintaining two states:
    	•	UI State
    Clients can replay most of the important UI from the provided EventMsg
    history.
    	•	Model State
    The model receives the complete session history to reconstruct its
    internal state.
    
    This design provides a solid foundation. If, in the future, more precise
    UI reconstruction is needed, we have two potential paths:
    1. Introduce a third data structure that allows us to derive both
    ResponseItems and EventMsgs.
    2. Clearly divide responsibilities: the core system ensures the
    integrity of the model state, while clients are responsible for
    reconstructing the UI.
  • Include originator in authentication URL parameters (#3117)
    Associates the client with an authentication session.
  • [tui] Update /mcp output (#3134)
    # Summary
    Quick update to clean up MCP output
    
    ## Testing
    - [x] Ran locally, confirmed output looked good
  • Add a common way to create HTTP client (#3110)
    Ensure User-Agent and originator are always sent.
  • feat: add Android/Termux support by gating arboard dependency (#2895)
    ## Summary
    
    This PR enables Codex to build and run on Android/Termux environments by
    conditionally gating the arboard clipboard dependency for Android
    targets.
    
    ## Key Changes
    
    - **Android Compatibility**: Gate arboard dependency for Android targets
    where clipboard access may be restricted
    - **Build Fixes**: Add missing tempfile::Builder import for image
    clipboard operations
    - **Code Cleanup**: Remove unnecessary parentheses to resolve formatting
    warnings
    
    ## Technical Details
    
    ### Clipboard Dependency Gating
    - Uses conditional compilation to exclude arboard on Android targets
    - Maintains full clipboard functionality on other platforms
    - Prevents build failures on Android/Termux where system clipboard
    access is limited
    
    ### Import Fixes
    - Adds missing tempfile::Builder import that was causing compilation
    errors
    - Ensures image clipboard operations work correctly when clipboard is
    available
    
    ## Platform Support
    
    -  **Linux/macOS/Windows**: Full clipboard functionality maintained
    -  **Android/Termux**: Builds successfully without clipboard dependency
    -  **Other Unix platforms**: Unchanged behavior
    
    ## Testing
    
    -  Builds successfully on Android/Termux
    -  Maintains clipboard functionality on supported platforms  
    -  No regression in existing functionality
    
    This addresses the Android/Termux compatibility issues while keeping
    clipboard functionality intact for platforms that support it.
  • TUI: fix MCP docs hyperlink in empty_mcp_output (#2907)
    - Summary:
    - Updated the hardcoded hyperlink shown when no MCP servers are
    configured to point at the canonical docs section:
        - From: codex-rs/config.md#mcp_servers (moved/obsolete)
        - To: docs/config.md#mcp_servers (correct GitHub path)
    - Rationale:
    - The TUI link was pointing to a file that only redirects; this makes
    the link accurate and reduces user confusion.
    - Validation:
    - Verified that the target anchor exists at:
    https://github.com/openai/codex/blob/main/docs/config.md#mcp_servers
    - UI behavior unchanged otherwise (rendering of link text remains “MCP
    docs”).
    - Impact:
    - One-line change in TUI display logic; no functional behavior change.
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • [feat] use experimental reasoning summary (#3071)
    <img width="1512" height="442" alt="Screenshot 2025-09-02 at 3 49 46 PM"
    src="https://github.com/user-attachments/assets/26c3c1cf-b7ed-4520-a12a-8d38a8e0c318"
    />
  • Move CodexAuth and AuthManager to the core crate (#3074)
    Fix a long standing layering issue.
  • Show loading state when @ search results are pending (#3061)
    ## Summary
    - allow selection popups to specify their empty state message
    - show a "loading..." placeholder in the file search popup while matches
    are pending
    - update other popup call sites to continue using a "no matches" message
    
    ## Testing
    - just fmt
    - just fix -p codex-tui
    - cargo test -p codex-tui
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68b73e956e90832caf4d04a75fcc9c46
  • prefer ratatui Stylized for constructing lines/spans (#3068)
    no functional change, just simplifying ratatui styling and adding
    guidance in AGENTS.md for future.
  • tui: fix occasional UI flicker (#2918)
    occasionally i was seeing some minor flickering when adding history
    lines. hopefully this clears it up.
  • tui: catch get_cursor_position errors (#2870)
    still seeing errors with reading back the cursor position in some cases;
    adding catches everywhere we might run into this.
  • tui: fix extra blank lines in streamed agent messages (#3065)
    Fixes excessive blank lines appearing during agent message streaming.
    
    - Only insert a separator blank line for new, non-streaming history
    cells.
    - Streaming continuations now append without adding a spacer,
    eliminating extra gaps between chunks.
    
    Affected area: TUI display of agent messages (tui/src/app.rs).
  • tui: hide '/init' suggestion when AGENTS.md exists (#3038)
    Hide the “/init” suggestion in the new-session banner when an
    `AGENTS.md` exists anywhere from the repo root down to the current
    working directory.
    
    Changes
    - Conditional suggestion: use `discover_project_doc_paths(config)` to
    suppress `/init` when agents docs are present.
    - TUI style cleanup: switch banner construction to `Stylize` helpers
    (`.bold()`, `.dim()`, `.into()`), avoiding `Span::styled`/`Span::raw`.
    - Fixture update: remove `/init` line in
    `tui/tests/fixtures/ideal-binary-response.txt` to match the new banner.
    
    Validation
    - Ran formatting and scoped lint fixes: `just fmt` and `just fix -p
    codex-tui`.
    - Tests: `cargo test -p codex-tui` passed (`176 passed, 0 failed`).
    
    Notes
    - No change to the `/init` command itself; only the welcome banner now
    adapts based on presence of `AGENTS.md`.
  • Bug fix: ignore Enter on empty input to avoid queuing blank messages (#3047)
    ## Summary
    Pressing Enter with an empty composer was treated as a submission, which
    queued a blank message while a task was running. This PR suppresses
    submission when there is no text and no attachments.
    
    ## Root Cause
    
    - ChatComposer returned Submitted even when the trimmed text was empty.
    ChatWidget then queued it during a running task, leading to an empty
    item appearing in the queued list and being popped later with no effect.
    
    ## Changes
    - ChatComposer Enter handling: if trimmed text is empty and there are no
    attached images, return None instead of Submitted.
    - No changes to ChatWidget; behavior naturally stops queuing blanks at
    the source.
    
    ## Code Paths
    
    - Modified: `tui/src/bottom_pane/chat_composer.rs`
    - Tests added:
        - `tui/src/bottom_pane/chat_composer.rs`: `empty_enter_returns_none`
    - `tui/src/chatwidget/tests.rs`:
    `empty_enter_during_task_does_not_queue`
    
    ## Result
    
    ### Before
    
    
    https://github.com/user-attachments/assets/a40e2f6d-42ba-4a82-928b-8f5458f5884d
    
    ### After
    
    
    
    https://github.com/user-attachments/assets/958900b7-a566-44fc-b16c-b80380739c92
  • remove extra quote from disabled-command message (#3035)
    there was an extra ' floating around for some reason.
  • fix: specify --profile to cargo clippy in CI (#2871)
    Today we had a breakage in the release build that went unnoticed by CI.
    Here is what happened:
    
    - https://github.com/openai/codex/pull/2242 originally added some logic
    to do release builds to prevent this from happening
    - https://github.com/openai/codex/pull/2276 undid that change to try to
    speed things up by removing the step to build all the individual crates
    in release mode, assuming the `cargo check` call was sufficient
    coverage, which it would have been, had it specified `--profile`
    
    This PR adds `--profile` to the `cargo check` step so we should get the
    desired coverage from our build matrix.
    
    Indeed, enabling this in our CI uncovered a warning that is only present
    in release mode that was going unnoticed.
  • Following up on #2371 post commit feedback (#2852)
    - Introduce websearch end to complement the begin 
    - Moves the logic of adding the sebsearch tool to
    create_tools_json_for_responses_api
    - Making it the client responsibility to toggle the tool on or off 
    - Other misc in #2371 post commit feedback
    - Show the query:
    
    <img width="1392" height="151" alt="image"
    src="https://github.com/user-attachments/assets/8457f1a6-f851-44cf-bcca-0d4fe460ce89"
    />
  • Custom /prompts (#2696)
    Adds custom `/prompts` to `~/.codex/prompts/<command>.md`.
    
    <img width="239" height="107" alt="Screenshot 2025-08-25 at 6 22 42 PM"
    src="https://github.com/user-attachments/assets/fe6ebbaa-1bf6-49d3-95f9-fdc53b752679"
    />
    
    ---
    
    Details:
    
    1. Adds `Op::ListCustomPrompts` to core.
    2. Returns `ListCustomPromptsResponse` with list of `CustomPrompt`
    (name, content).
    3. TUI calls the operation on load, and populates the custom prompts
    (excluding prompts that collide with builtins).
    4. Selecting the custom prompt automatically sends the prompt to the
    agent.
  • UI: Make slash commands bold in welcome message (#2762)
    ## What
    Make slash commands (/init, /status, /approvals, /model) bold and white
    in the welcome message for better visibility.
    <img width="990" height="286" alt="image"
    src="https://github.com/user-attachments/assets/13f90e96-b84a-4659-aab4-576d84a31af7"
    />
    
    
    ## Why
    The current welcome message displays all text in a dimmed style, making
    the slash commands less prominent. Users need to quickly identify
    available commands when starting Codex.
    
    ## How
    Modified `tui/src/history_cell.rs` in the `new_session_info` function
    to:
    - Split each command line into separate spans
    - Apply bold white styling to command text (`/init`, `/status`, etc.)
    - Keep descriptions dimmed for visual contrast
    - Maintain existing layout and spacing
    
    ## Test plan
    - [ ] Run the TUI and verify commands appear bold in the welcome message
    - [ ] Ensure descriptions remain dimmed for readability
    - [ ] Confirm all existing tests pass
  • burst paste edge cases (#2683)
    This PR fixes two edge cases in managing burst paste (mainly on power
    shell).
    Bugs:
    - Needs an event key after paste to render the pasted items
    
    > ChatComposer::flush_paste_burst_if_due() flushes on timeout. Called:
    >     - Pre-render in App on TuiEvent::Draw.
    >     - Via a delayed frame
    >
    BottomPane::request_redraw_in(ChatComposer::recommended_paste_flush_delay()).
    
    - Parses two key events separately before starting parsing burst paste
    
    > When threshold is crossed, pull preceding burst chars out of the
    textarea and prepend to paste_burst_buffer, then keep buffering.
    
    - Integrates with #2567 to bring image pasting to windows.
  • disallow some slash commands while a task is running (#2792)
    /new, /init, /models, /approvals, etc. don't work correctly during a
    turn. disable them.
  • Add "View Image" tool (#2723)
    Adds a "View Image" tool so Codex can find and see images by itself:
    
    <img width="1772" height="420" alt="Screenshot 2025-08-26 at 10 40
    04 AM"
    src="https://github.com/user-attachments/assets/7a459c7b-0b86-4125-82d9-05fbb35ade03"
    />
  • fix cursor after suspend (#2690)
    This was supposed to be fixed by #2569, but I think the actual fix got
    lost in the refactoring.
    
    Intended behavior: pressing ^Z moves the cursor below the viewport
    before suspending.
  • fix (most) doubled lines and hanging list markers (#2789)
    This was mostly written by codex under heavy guidance via test cases
    drawn from logged session data and fuzzing. It also uncovered some bugs
    in tui_markdown, which will in some cases split a list marker from the
    list item content. We're not addressing those bugs for now.
  • send context window with task started (#2752)
    - Send context window with task started
    - Accounting for changing the model per turn
  • Cache transcript wraps (#2739)
    Previously long transcripts would become unusable.
  • Fix crash when backspacing placeholders adjacent to multibyte text (#2674)
    Prevented panics when deleting placeholders near multibyte characters by
    clamping the cursor to a valid boundary and using get-based slicing
    
    Added a regression test to ensure backspacing after multibyte text
    leaves placeholders intact without crashing
    
    ---------
    
    Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
  • fix emoji spacing (#2735)
    before:
    <img width="295" height="266" alt="Screenshot 2025-08-26 at 5 05 03 PM"
    src="https://github.com/user-attachments/assets/3e876f08-26d0-407e-a995-28fd072e288f"
    />
    
    after:
    <img width="295" height="129" alt="Screenshot 2025-08-26 at 5 05 30 PM"
    src="https://github.com/user-attachments/assets/2a019d52-19ed-40ef-8155-4f02c400796a"
    />
  • fix transcript lines being added to diff view (#2721)
    This fixes a bug where if you ran /diff while at turn was running,
    transcript lines would be added to the end of the diff view. Also,
    refactor to make this kind of issue less likely in future.
  • fix issue #2713: adding support for alt+ctrl+h to delete backward word (#2717)
    This pr addresses the fix for
    https://github.com/openai/codex/issues/2713
    
    ### Changes:
      - Added key handler for `Alt+Ctrl+H` → `delete_backward_word()`
    - Added test coverage in `delete_backward_word_alt_keys()` that verifies
    both:
        - Standard `Alt+Backspace` binding continues to work
    - New `Alt+Ctrl+H` binding works correctly for backward word deletion
    
    ### Testing:
      The test ensures both key combinations produce identical behavior:
      - Delete the previous word from "hello world" → "hello "
      - Cursor positioned correctly after deletion
    
    ###  Backward Compatibility:
    This change is backward compatible - existing `Alt+Backspace`
    functionality remains unchanged while adding support for the
    terminal-specific `Alt+Ctrl+H` variant