Commit Graph

955 Commits

  • change collaboration mode to struct (#9793)
    Shouldn't cause behavioral change
  • Print warning if we skip config loading (#9611)
    https://github.com/openai/codex/pull/9533 silently ignored config if
    untrusted. Instead, we still load it but disable it. Maybe we shouldn't
    try to parse it either...
    
    <img width="939" height="515" alt="Screenshot 2026-01-21 at 14 56 38"
    src="https://github.com/user-attachments/assets/e753cc22-dd99-4242-8ffe-7589e85bef66"
    />
  • Persist text element ranges and attached images across history/resume (#9116)
    **Summary**
    - Backtrack selection now rehydrates `text_elements` and
    `local_image_paths` from the chosen user history cell so Esc‑Esc history
    edits preserve image placeholders and attachments.
    - Composer prefill uses the preserved elements/attachments in both `tui`
    and `tui2`.
    - Extended backtrack selection tests to cover image placeholder elements
    and local image paths.
    
    **Changes**
    - `tui/src/app_backtrack.rs`: Backtrack selection now carries text
    elements + local image paths; composer prefill uses them (removes TODO).
    - `tui2/src/app_backtrack.rs`: Same as above.
    - `tui/src/app.rs`: Updated backtrack test to assert restored
    elements/paths.
    - `tui2/src/app.rs`: Same test updates.
    
    ### The original scope of this PR (threading text elements and image
    attachments through the codex harness thoroughly/persistently) was
    broken into the following PRs other than this one:
    
    The diff of this PR was reduced by changing types in a starter PR:
    https://github.com/openai/codex/pull/9235
    
    Then text element metadata was added to protocol, app server, and core
    in this PR: https://github.com/openai/codex/pull/9331
    
    Then the end-to-end flow was completed by wiring TUI/TUI2 input,
    history, and restore behavior in
    https://github.com/openai/codex/pull/9393
    
    Prompt expansion was supported in this PR:
    https://github.com/openai/codex/pull/9518
    
    TextElement optional placeholder field was protected in
    https://github.com/openai/codex/pull/9545
  • Hide mode cycle hint while a task is running (#9730)
    ## Summary
    - hide the “(shift+tab to cycle)” suffix on the collaboration mode label
    while a task is running
    - keep the cycle hint visible when idle
    - add a snapshot to cover the running-task label state
  • TUI: prompt to implement plan and switch to Execute (#9712)
    ## Summary
    - Replace the plan‑implementation prompt with a standard selection
    popup.
    - “Yes” submits a user turn in Execute via a dedicated app event to
    preserve normal transcript behavior.
    - “No” simply dismisses the popup.
    
    <img width="977" height="433" alt="Screenshot 2026-01-22 at 2 00 54 PM"
    src="https://github.com/user-attachments/assets/91fad06f-7b7a-4cd8-9051-f28a19b750b2"
    />
    
    ## Changes
    - Add a plan‑implementation popup using `SelectionViewParams`.
    - Add `SubmitUserMessageWithMode` so “Yes” routes through
    `submit_user_message` (ensures user history + separator state).
    - Track `saw_plan_update_this_turn` so the prompt appears even when only
    `update_plan` is emitted.
    - Suppress the plan popup on replayed turns, when messages are queued,
    or when a rate‑limit prompt is pending.
    - Add `execute_mode` helper for collaboration modes.
    - Add tests for replay/queued/rate‑limit guards and plan update without
    final message.
    - Add snapshots for both the default and “No”‑selected popup states.
  • feat(core) update Personality on turn (#9644)
    ## Summary
    Support updating Personality mid-Thread via UserTurn/OverwriteTurn. This
    is explicitly unused by the clients so far, to simplify PRs - app-server
    and tui implementations will be follow-ups.
    
    ## Testing
    - [x] added integration tests
  • Modes label below textarea (#9645)
    # Summary
    - Add a collaboration mode indicator rendered at the bottom-right of the
    TUI composer footer.
    - Style modes per design (Plan in #D72EE1, Execute matching dim context
    style, Pair Programming using the same cyan as text elements).
    - Add shared “(shift+tab to cycle)” hint text for all mode labels and
    align the indicator with the left footer margin.
    
    NOTE: currently this is hidden if the Collaboration Modes feature flag
    is disabled, or in Custom mode. Maybe we should show it in Custom mode
    too? I'll leave that out of this PR though
    
    # UI
    - Mode indicator appears below the textarea, bottom-right of the footer
    line.
    - Includes “(shift+tab to cycle)” and keeps right padding aligned to the
    left footer indent.
    
    <img width="983" height="200" alt="Screenshot 2026-01-21 at 7 17 54 PM"
    src="https://github.com/user-attachments/assets/d1c5e4ed-7d7b-4f6c-9e71-bc3cf6400e0e"
    />
    
    <img width="980" height="200" alt="Screenshot 2026-01-21 at 7 18 53 PM"
    src="https://github.com/user-attachments/assets/d22ff0da-a406-4930-85c5-affb2234e84b"
    />
    
    <img width="979" height="201" alt="Screenshot 2026-01-21 at 7 19 12 PM"
    src="https://github.com/user-attachments/assets/862cb17f-0495-46fa-9b01-a4a9f29b52d5"
    />
  • feat(tui) /permissions flow (#9561)
    ## Summary
    Adds the `/permissions` command, with a (usually) shorter set of
    permissions. `/approvals` still exists, for backwards compatibility.
    
    <img width="863" height="309" alt="Screenshot 2026-01-20 at 4 12 51 PM"
    src="https://github.com/user-attachments/assets/c49b5ba5-bc47-46dd-9067-e1a5670328fe"
    />
    
    
    ## Testing
    - [x] updated unit tests
    - [x] Tested locally
  • Add UI for skill enable/disable. (#9627)
    "/skill" will now allow you to enable/disable skills:
    <img width="658" height="199" alt="image"
    src="https://github.com/user-attachments/assets/bf8994c8-d6c1-462f-8bbb-f1ee9241caa4"
    />
  • feat(tui): retire the tui2 experiment (#9640)
    ## Summary
    - Retire the experimental TUI2 implementation and its feature flag.
    - Remove TUI2-only config/schema/docs so the CLI stays on the
    terminal-native path.
    - Keep docs aligned with the legacy TUI while we focus on redraw-based
    improvements.
    
    ## Customer impact
    - Retires the TUI2 experiment and keeps Codex on the proven
    terminal-native UI while we invest in redraw-based improvements to the
    existing experience.
    
    ## Migration / compatibility
    - If you previously set tui2-related options in config.toml, they are
    now ignored and Codex continues using the existing terminal-native TUI
    (no action required).
    
    ## Context
    - What worked: a transcript-owned viewport delivered excellent resize
    rewrap and high-fidelity copy (especially for code).
    - Why stop: making that experience feel fully native across the
    environment matrix (terminal emulator, OS, input modality, multiplexer,
    font/theme, alt-screen behavior) creates a combinatorial explosion of
    edge cases.
    - What next: we are focusing on redraw-based improvements to the
    existing terminal-native TUI so scrolling, selection, and copy remain
    native while resize/redraw correctness improves.
    
    ## Testing
    - just write-config-schema
    - just fmt
    - cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs
    -p codex-core
    - cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs
    -p codex-cli
    - cargo check
    - cargo test -p codex-core
    - cargo test -p codex-cli
  • Reduce burst testing flake (#9549)
    ## Summary
    
    - make paste-burst tests deterministic by injecting explicit timestamps
    instead of relying on wall clock timing
    - add time-aware helpers for input/submission paths so tests can drive
    the burst heuristic precisely
    - update burst-related tests to flush using computed timeouts while
    preserving behavior assertions
    - increase timeout slack in
    shell_tools_start_before_response_completed_when_stream_delayed to
    reduce flakiness
  • fix(tui) turn timing incremental (#9599)
    ## Summary
    When we send multiple assistant messages, reset the timer so "Worked for
    2m 36s" is the time since the last time we showed the message, rather
    than an ever-increasing number.
    
    We could instead change the copy so it's more clearly a running counter.
    
    ## Testing
    - [x] ran locally
    
    <img width="903" height="732" alt="Screenshot 2026-01-21 at 1 42 51 AM"
    src="https://github.com/user-attachments/assets/bb4d827b-3a0e-48ba-bd6a-d8cd65d8e892"
    />
  • feat: better sorting of shell commands (#9629)
    This PR changes the way we sort slash command by going in this order:
    1. Exact match
    2. Prefix
    3. Fuzzy
    
    As a result, we you type `/ps` the default command is not `/approvals`
  • Chore: update plan mode output in prompt (#9592)
    ### Summary
    * Update plan prompt output
    * Update requestUserInput response to be a single key value pair
    `answer: String`.
  • define/emit some metrics for windows sandbox setup (#9573)
    This should give us visibility into how users are using the elevated
    sandbox nux flow, and the timing of the elevated setup.
  • nit: better collab tui (#9551)
    <img width="478" height="304" alt="Screenshot 2026-01-21 at 11 53 50"
    src="https://github.com/user-attachments/assets/e2ef70de-2fff-44e0-a574-059177966ed2"
    />
  • Add request-user-input overlay (#9585)
    - Add request-user-input overlay and routing in the TUI
  • Prompt Expansion: Preserve Text Elements (#9518)
    Summary
    - Preserve `text_elements` through custom prompt argument parsing and
    expansion (named and numeric placeholders).
    - Translate text element ranges through Shlex parsing using sentinel
    substitution, and rehydrate text + element ranges per arg.
    - Drop image attachments when their placeholder does not survive prompt
    expansion, keeping attachments consistent with rendered elements.
    - Mirror changes in TUI2 and expand tests for prompt parsing/expansion
    edge cases.
    
    Tests
    - placeholders with spaces as single tokens (positional + key=value,
    quoted + unquoted),
      - prompt expansion with image placeholders,
      - large paste + image arg combinations,
      - unused image arg dropped after expansion.
  • Show session header before configuration (#9568)
    We were skipping if we know the model. We shouldn't
  • [codex-tui] exit when terminal is dumb (#9293)
    Using terminal with TERM=dumb specifically mean that TUIs and the like
    don't work. Ensure that codex doesn't run in these environments and exit
    with odd errors like crossterm's "Error: The cursor position could not
    be read within a normal duration"
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Improve UI spacing for queued messages (#9162)
    Despite good spacing between queued messages and assistant message text:
    <img width="462" height="322" alt="Screenshot 2026-01-12 at 4 54 50 PM"
    src="https://github.com/user-attachments/assets/e8b46252-0b33-40d2-b431-cb73b9a3bd2e"
    />
    
    Codex has confusing spacing between queued messages and shimmering
    status text (making the queued message seem like a sub-item of the
    shimmering status text)
    <img width="615" height="217" alt="Screenshot 2026-01-12 at 4 54 18 PM"
    src="https://github.com/user-attachments/assets/ee5e6095-8fe9-4863-88d2-10472cab8bd6"
    />
    
    This PR changes the spacing between the queued message(s) and shimmering
    status text to make it less confusing:
    <img width="440" height="240" alt="Screenshot 2026-01-13 at 11 20 36 AM"
    src="https://github.com/user-attachments/assets/02dcc690-cbe9-4943-87de-c7300ef51120"
    />
    
    While working on the status/queued spacing change, we noticed two
    paste‑burst tests were timing‑sensitive and could fail
    on slower CI. We added a small test‑only helper to keep the paste‑burst
    state active and refreshed during these tests. This
    removes dependence on tight timing and makes the tests deterministic
    without affecting runtime behavior.
  • Add total (non-partial) TextElement placeholder accessors (#9545)
    ## Summary
    - Make `TextElement` placeholders private and add a text-backed accessor
    to avoid assuming `Some`.
    - Since they are optional in the protocol, we want to make sure any
    accessors properly handle the None case (getting the placeholder using
    the byte range in the text)
    - Preserve placeholders during protocol/app-server conversions using the
    accessor fallback.
    - Update TUI composer/remap logic and tests to use the new
    constructor/accessor.
  • Fixed config merging issue with profiles (#9509)
    This PR fixes a small issue with chained (layered) config.toml file
    merging. The old logic didn't properly handle profiles.
    
    In particular, if a lower-layer config overrides a profile defined in a
    higher-layer config, the override did not take effect. This prevents
    users from having project-specific profile overrides and contradicts the
    (soon-to-be) documented behavior of config merging.
    
    The change adds a unit test for this case. It also exposes a function
    from the config crate that is needed by the app server code paths to
    implement support for layered configs.
  • Tui: use collaboration mode instead of model and effort (#9507)
    - Only use collaboration modes in the tui state to track model and
    effort.
    - No behavior change without the collaboration modes flag.
    - Change model and effort on /model, /collab (behind a flag), and
    shift+tab (behind flag)
  • nit: do not render terminal interactions if no task running (#9374)
    To prevent race where the terminal interaction message is processed
    after the last message
  • fix(tui) fix user message light mode background (#9407)
    ## Summary
    Fixes the user message styles for light mode.
    
    ## Testing
    Attaching 2 screenshots from ghostty, but I also tried various styles in
    Terminal.app and iTerm2.
    **Before**
    <img width="888" height="560" alt="Screenshot 2026-01-16 at 5 22 36 PM"
    src="https://github.com/user-attachments/assets/73d9decb-a01a-4ece-b88e-ea49a33cc0c6"
    />
    
    **After**
    <img width="890" height="281" alt="Screenshot 2026-01-16 at 5 22 59 PM"
    src="https://github.com/user-attachments/assets/6689e286-d699-4ceb-b0cb-579a31b047bf"
    />
  • Persist text elements through TUI input and history (#9393)
    Continuation of breaking up this PR
    https://github.com/openai/codex/pull/9116
    
    ## Summary
    - Thread user text element ranges through TUI/TUI2 input, submission,
    queueing, and history so placeholders survive resume/edit flows.
    - Preserve local image attachments alongside text elements and rehydrate
    placeholders when restoring drafts.
    - Keep model-facing content shapes clean by attaching UI metadata only
    to user input/events (no API content changes).
    
    ## Key Changes
    - TUI/TUI2 composer now captures text element ranges, trims them with
    text edits, and restores them when submission is suppressed.
    - User history cells render styled spans for text elements and keep
    local image paths for future rehydration.
    - Initial chat widget bootstraps accept empty `initial_text_elements` to
    keep initialization uniform.
    - Protocol/core helpers updated to tolerate the new InputText field
    shape without changing payloads sent to the API.
  • Migrate tui to use UserTurn (#9497)
    - `tui/` and `tui2/` submit `Op::UserTurn` and own full turn context
    (cwd/approval/sandbox/model/etc.).
    - `Op::UserInput` is documented as legacy in `codex-protocol` (doc-only;
    no `#[deprecated]` to avoid `-D warnings` fallout).
    - Remove obsolete `#[allow(deprecated)]` and the unused `ConversationId`
    alias/re-export.
  • tui: avoid Esc interrupt when skill popup active (#9451)
    Fixes #9450
    
    ## What
    - When a task is running and the skills autocomplete popup is open,
    `Esc` now dismisses the popup instead of sending `Op::Interrupt`.
    - `Esc` still interrupts a running task when no popup is active.
    
    ## Tests
    - `cargo test -p codex-tui`
    
    ---------
    
    Co-authored-by: prateek <199982+prateek@users.noreply.github.com>
  • Feat: request user input tool (#9472)
    ### Summary
    * Add `requestUserInput` tool that the model can use for gather
    feedback/asking question mid turn.
    
    
    ### Tool input schema
    ```
    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "title": "requestUserInput input",
      "type": "object",
      "additionalProperties": false,
      "required": ["questions"],
      "properties": {
        "questions": {
          "type": "array",
          "description": "Questions to show the user (1-3). Prefer 1 unless multiple independent decisions block progress.",
          "minItems": 1,
          "maxItems": 3,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["id", "header", "question"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable identifier for mapping answers (snake_case)."
              },
              "header": {
                "type": "string",
                "description": "Short header label shown in the UI (12 or fewer chars)."
              },
              "question": {
                "type": "string",
                "description": "Single-sentence prompt shown to the user."
              },
              "options": {
                "type": "array",
                "description": "Optional 2-3 mutually exclusive choices. Put the recommended option first and suffix its label with \"(Recommended)\". Only include \"Other\" option if we want to include a free form option. If the question is free form in nature, do not include any option.",
                "minItems": 2,
                "maxItems": 3,
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["value", "label", "description"],
                  "properties": {
                    "value": {
                      "type": "string",
                      "description": "Machine-readable value (snake_case)."
                    },
                    "label": {
                      "type": "string",
                      "description": "User-facing label (1-5 words)."
                    },
                    "description": {
                      "type": "string",
                      "description": "One short sentence explaining impact/tradeoff if selected."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    ```
    
    ### Tool output schema
    ```
    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "title": "requestUserInput output",
      "type": "object",
      "additionalProperties": false,
      "required": ["answers"],
      "properties": {
        "answers": {
          "type": "object",
          "description": "Map of question id to user answer.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": false,
            "required": ["selected"],
            "properties": {
              "selected": {
                "type": "array",
                "items": { "type": "string" }
              },
              "other": {
                "type": ["string", "null"]
              }
            }
          }
        }
      }
    }
    ```
  • TUI: collaboration mode UX + always submit UserTurn when enabled (#9461)
    - Adds experimental collaboration modes UX in TUI: Plan / Pair
    Programming / Execute.
    - Gated behind `Feature::CollaborationModes`; existing behavior remains
    unchanged when disabled.
    - Selection UX:
    - `Shift+Tab` cycles modes while idle (no task running, no modal/popup).
    - `/collab` cycles; `/collab <plan|pair|pp|execute|exec>` sets
    explicitly.
    - Footer flash after changes + shortcut overlay shows `Shift+Tab` “to
    change mode”.
      - `/status` shows “Collaboration mode”.
    - Submission semantics:
    - When enabled: every submit uses `Op::UserTurn` and always includes
    `collaboration_mode: Some(...)` (default Pair Programming).
      - Removes the one-shot “pending collaboration mode” behavior.
    - Implementation:
    - New `tui/src/collaboration_modes.rs` (selection enum/cycle, `/collab`
    parsing, resolve to `CollaborationMode`, footer flash line).
    - Fallback: `resolve_mode_or_fallback` synthesizes a `CollaborationMode`
    when presets are missing (uses current model + reasoning effort; no
    `developer_instructions`) to avoid core falling back to `Custom`.
      - TODO: migrate TUI to use `Op::UserTurn`.
  • Fixed TUI regression related to image paste in WSL (#9473)
    This affects quoted paths in WSL. The fix is to normalize quoted Windows
    paths before WSL conversion.
    
    This addresses #9456
  • tui: allow forward navigation in backtrack preview (#9059)
    Fixes #9058
    
    ## Summary
    When the transcript backtrack preview is armed (press `Esc`), allow
    navigating to newer user messages with the `→` arrow, in addition to
    navigating backwards with `Esc`/`←`, before confirming with `Enter`.
    
    ## Changes
    - Backtrack preview navigation: `Esc`/`←` steps to older user messages,
    `→` steps to newer ones, `Enter` edits the selected message (clamped at
    bounds, no wrap-around).
    - Transcript overlay footer hints updated to advertise `esc/←`, `→`, and
    `enter` when a message is highlighted.
    
    ## Related
    - WSL shortcut-overlay snapshot determinism: #9359
    
    ## Testing
    - `just fmt`
    - `just fix -p codex-tui`
    - `just fix -p codex-tui2`
    - `cargo test -p codex-tui app_backtrack::`
    - `cargo test -p codex-tui pager_overlay::`
    - `cargo test -p codex-tui2 app_backtrack::`
    - `cargo test -p codex-tui2 pager_overlay::`
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Preserve slash command order in search (#9425)
    Keep slash popup search results in presentation order for built-ins and
    prompts.
  • chore(instructions) Remove unread SessionMeta.instructions field (#9423)
    ### Description
    - Remove the now-unused `instructions` field from the session metadata
    to simplify SessionMeta and stop propagating transient instruction text
    through the rollout recorder API. This was only saving
    user_instructions, and was never being read.
    - Stop passing user instructions into the rollout writer at session
    creation so the rollout header only contains canonical session metadata.
    
    ### Testing
    
    - Ran `just fmt` which completed successfully.
    - Ran `just fix -p codex-protocol`, `just fix -p codex-core`, `just fix
    -p codex-app-server`, `just fix -p codex-tui`, and `just fix -p
    codex-tui2` which completed (Clippy fixes applied) as part of
    verification.
    - Ran `cargo test -p codex-protocol` which passed (28 tests).
    - Ran `cargo test -p codex-core` which showed failures in a small set of
    tests (not caused by the protocol type change directly):
    `default_client::tests::test_create_client_sets_default_headers`,
    several `models_manager::manager::tests::refresh_available_models_*`,
    and `shell_snapshot::tests::linux_sh_snapshot_includes_sections` (these
    tests failed in this CI run).
    - Ran `cargo test -p codex-app-server` which reported several failing
    integration tests (including
    `suite::codex_message_processor_flow::test_codex_jsonrpc_conversation_flow`,
    `suite::output_schema::send_user_turn_*`, and
    `suite::user_agent::get_user_agent_returns_current_codex_user_agent`).
    - `cargo test -p codex-tui` and `cargo test -p codex-tui2` were
    attempted but aborted due to disk space exhaustion (`No space left on
    device`).
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_696bd8ce632483228d298cf07c7eb41c)
  • fix(tui) Defer backtrack trim until rollback confirms (#9401)
    Document the backtrack/rollback state machine and invariants between the
    transcript overlay, in-flight “live tail”, and core thread state (tui + tui2).
    
    Also adjust behavior for correctness:
    - Track a single pending rollback and block additional rollbacks until core responds.
    - Defer trimming transcript cells until ThreadRolledBack for the active session.
    - Clear the guard on ThreadRollbackFailed so the user can retry.
    - After a confirmed trim, schedule a one-shot scrollback refresh on the next draw.
    - Clear stale pending rollback state when switching sessions.
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Support enable/disable skill via config/api. (#9328)
    In config.toml:
    ```
    [[skills.config]]
    path = "/Users/xl/.codex/skills/my_skill/SKILL.md"
    enabled = false
    ```
    
    API:
    skills/list, skills/config/write
  • feat: show forked from session id in /status (#9330)
    Summary:
    - Add forked_from to SessionMeta/SessionConfiguredEvent and persist it
    for forked sessions.
    - Surface forked_from in /status for tui + tui2 and add snapshots.