Commit Graph

3066 Commits

  • fix: update resource path resolution logic so it works with Bazel (#8861)
    The Bazelification work in-flight over at
    https://github.com/openai/codex/pull/8832 needs this fix so that Bazel
    can find the path to the DotSlash file for `bash`.
    
    With this change, the following almost works:
    
    ```
    bazel test --test_output=errors //codex-rs/exec-server:exec-server-all-test
    ```
    
    That is, now the `list_tools` test passes, but
    `accept_elicitation_for_prompt_rule` still fails because it runs
    Seatbelt itself, so it needs to be run outside Bazel's local sandboxing.
  • Feat: appServer.requirementList for requirement.toml (#8800)
    ### Summary
    We are exposing requirements via `requirement/list` method from
    app-server so that we can conditionally disable the agent mode dropdown
    selection in VSCE and correctly setting the default value.
    
    ### Sample output
    #### `etc/codex/requirements.toml`
    <img width="497" height="49" alt="Screenshot 2026-01-06 at 11 32 06 PM"
    src="https://github.com/user-attachments/assets/fbd9402e-515f-4b9e-a158-2abb23e866a0"
    />
    
    #### App server response
    <img width="1107" height="79" alt="Screenshot 2026-01-06 at 11 30 18 PM"
    src="https://github.com/user-attachments/assets/c0d669cd-54ef-4789-a26c-adb2c41950af"
    />
  • Support symlink for skills discovery. (#8801)
    Skills discovery now follows symlink entries for SkillScope::User
    ($CODEX_HOME/skills) and SkillScope::Admin (e.g. /etc/codex/skills).
    
    Added cycle protection: directories are canonicalized and tracked in a
    visited set to prevent infinite traversal from circular links.
    
    Added per-root traversal limits to avoid accidentally scanning huge
    trees:
    - max depth: 6
    - max directories: 2000 (logs a warning if truncated)
    
    For now, symlink stat failures and traversal truncation are logged
    rather than surfaced as UI “invalid SKILL.md” warnings.
  • Warn in /model if BASE_URL set (#8847)
    <img width="763" height="349" alt="Screenshot 2026-01-07 at 18 37 59"
    src="https://github.com/user-attachments/assets/569d01cb-ea91-4113-889b-ba74df24adaf"
    />
    
    It may not make sense to use the `/model` menu with a custom
    OPENAI_BASE_URL. But some model proxies may support it, so we shouldn't
    disable it completely. A warning is a reasonable compromise.
  • Clarify YAML frontmatter formatting in skill-creator (#8610)
    Fixes #8609
    
    # Summary
    
    Emphasize single-line name/description values and quoting when values
    could be interpreted as YAML syntax.
    
    # Testing
    
    Not run (skill-only change.)
  • Add feature for optional request compression (#8767)
    Adds a new feature
    `enable_request_compression` that will compress using zstd requests to
    the codex-backend. Currently only enabled for codex-backend so only enabled for openai providers when using chatgpt::auth even when the feature is enabled
    
    Added a new info log line too for evaluating the compression ratio and
    overhead off compressing before requesting. You can enable with
    `RUST_LOG=$RUST_LOG,codex_client::transport=info`
    
    ```
    2026-01-06T00:09:48.272113Z  INFO codex_client::transport: Compressed request body with zstd pre_compression_bytes=28914 post_compression_bytes=11485 compression_duration_ms=0
    ```
  • Override truncation policy at model info level (#8856)
    We used to override truncation policy by comparing model info vs config
    value in context manager. A better way to do it is to construct model
    info using the config value
  • fix: implement 'Allow this session' for apply_patch approvals (#8451)
    **Summary**
    This PR makes “ApprovalDecision::AcceptForSession / don’t ask again this
    session” actually work for `apply_patch` approvals by caching approvals
    based on absolute file paths in codex-core, properly wiring it through
    app-server v2, and exposing the choice in both TUI and TUI2.
    - This brings `apply_patch` calls to be at feature-parity with general
    shell commands, which also have a "Yes, and don't ask again" option.
    - This also fixes VSCE's "Allow this session" button to actually work.
    
    While we're at it, also split the app-server v2 protocol's
    `ApprovalDecision` enum so execpolicy amendments are only available for
    command execution approvals.
    
    **Key changes**
    - Core: per-session patch approval allowlist keyed by absolute file
    paths
    - Handles multi-file patches and renames/moves by recording both source
    and destination paths for `Update { move_path: Some(...) }`.
    - Extend the `Approvable` trait and `ApplyPatchRuntime` to work with
    multiple keys, because an `apply_patch` tool call can modify multiple
    files. For a request to be auto-approved, we will need to check that all
    file paths have been approved previously.
    - App-server v2: honor AcceptForSession for file changes
    - File-change approval responses now map AcceptForSession to
    ReviewDecision::ApprovedForSession (no longer downgraded to plain
    Approved).
    - Replace `ApprovalDecision` with two enums:
    `CommandExecutionApprovalDecision` and `FileChangeApprovalDecision`
    - TUI / TUI2: expose “don’t ask again for these files this session”
    - Patch approval overlays now include a third option (“Yes, and don’t
    ask again for these files this session (s)”).
        - Snapshot updates for the approval modal.
    
    **Tests added/updated**
    - Core:
    - Integration test that proves ApprovedForSession on a patch skips the
    next patch prompt for the same file
    - App-server:
    - v2 integration test verifying
    FileChangeApprovalDecision::AcceptForSession works properly
    
    **User-visible behavior**
    - When the user approves a patch “for session”, future patches touching
    only those previously approved file(s) will no longer prompt gain during
    that session (both via app-server v2 and TUI/TUI2).
    
    **Manual testing**
    Tested both TUI and TUI2 - see screenshots below.
    
    TUI:
    <img width="1082" height="355" alt="image"
    src="https://github.com/user-attachments/assets/adcf45ad-d428-498d-92fc-1a0a420878d9"
    />
    
    
    TUI2:
    <img width="1089" height="438" alt="image"
    src="https://github.com/user-attachments/assets/dd768b1a-2f5f-4bd6-98fd-e52c1d3abd9e"
    />
  • Fix app-server write_models_cache to treat models with less priority number as higher priority. (#8844)
    Rank models with p0 higher than p1. This shouldn't result in any
    behavioral changes. Just reordering.
  • remove unnecessary todos (#8842)
    > // todo(aibrahim): why are we passing model here while it can change?
    
    we update it on each turn with `.with_model`
    
    > //TODO(aibrahim): run CI in release mode.
    
    although it's good to have, release builds take double the time tests
    take.
    
    > // todo(aibrahim): make this async function
    
    we figured out another way of doing this sync
  • Merge Modelfamily into modelinfo (#8763)
    - Merge ModelFamily into ModelInfo
    - Remove logic for adding instructions to apply patch
    - Add compaction limit and visible context window to `ModelInfo`
  • fix: upgrade lru crate to 0.16.3 (#8845)
    See https://rustsec.org/advisories/RUSTSEC-2026-0002.
    
    Though our `ratatui` fork has a transitive dep on an older version of
    the `lru` crate, so to get CI green ASAP, this PR also adds an exception
    to `deny.toml` for `RUSTSEC-2026-0002`, but hopefully this will be
    short-lived.
  • Move tests below auth manager (#8840)
    To simplify future diffs
  • chore: unify conversation with thread name (#8830)
    Done and verified by Codex + refactor feature of RustRover
  • fix: handle /review arguments in TUI (#8823)
    Handle /review <instructions> in the TUI and TUI2 by routing it as a
    custom review command instead of plain text, wiring command dispatch and
    adding composer coverage so typing /review text starts a review directly
    rather than posting a message. User impact: /review with arguments now
    kicks off the review flow, previously it would just forward as a plain
    command and not actually start a review.
  • fix: parse git apply paths correctly (#8824)
    Fixes apply.rs path parsing so 
    - quoted diff headers are tokenized and extracted correctly, 
    - /dev/null headers are ignored before prefix stripping to avoid bogus
    dev/null paths, and
    - git apply output paths are unescaped from C-style quoting.
    
    **Why**
    This prevents potentially missed staging and misclassified paths when
    applying or reverting patches, which could lead to incorrect behavior
    for repos with spaces or escaped characters in filenames.
    
    **Impact**
    I checked and this is only used in the cloud tasks support and `codex
    apply <task_id>` flow.
  • chore: stabilize core tool parallelism test (#8805)
    Set login=false for the shell tool in the timing-based parallelism test
    so it does not depend on slow user login shells, making the test
    deterministic without user-facing changes. This prevents occasional
    flakes when running locally.
  • Enable model upgrade popup even when selected model is no longer in picker (#8802)
    With `config.toml`:
    ```
    model = "gpt-5.1-codex"
    ```
    (where `gpt-5.1-codex` has `show_in_picker: false` in
    [`model_presets.rs`](https://github.com/openai/codex/blob/main/codex-rs/core/src/models_manager/model_presets.rs);
    this happens if the user hasn't used codex in a while so they didn't see
    the popup before their model was changed to `show_in_picker: false`)
    
    The upgrade picker used to not show (because `gpt-5.1-codex` was
    filtered out of the model list in code). Now, the filtering is done
    downstream in tui and app-server, so the model upgrade popup shows:
    
    <img width="1503" height="227" alt="Screenshot 2026-01-06 at 5 04 37 PM"
    src="https://github.com/user-attachments/assets/26144cc2-0b3f-4674-ac17-e476781ec548"
    />
  • fix: truncate long approval prefixes when rendering (#8734)
    Fixes inscrutable multiline approval requests:
    <img width="686" height="844" alt="image"
    src="https://github.com/user-attachments/assets/cf9493dc-79e6-4168-8020-0ef0fe676d5e"
    />
  • add web_search_cached flag (#8795)
    Add `web_search_cached` feature to config. Enables `web_search` tool
    with access only to cached/indexed results (see
    [docs](https://platform.openai.com/docs/guides/tools-web-search#live-internet-access)).
    
    This takes precedence over the existing `web_search_request`, which
    continues to enable `web_search` over live results as it did before.
    
    `web_search_cached` is disabled for review mode, as `web_search_request`
    is.
  • [app-server] fix config loading for conversations (#8765)
    Currently we don't load config properly for app server conversations.
    see:
    https://linear.app/openai/issue/CODEX-3956/config-flags-not-respected-in-codex-app-server.
    This PR fixes that by respecting the config passed in.
    
    Tested by running `cargo build -p codex-cli &&
    RUST_LOG=codex_app_server=debug CODEX_BIN=target/debug/codex cargo run
    -p codex-app-server-test-client -- \
    --config
    model_providers.mock_provider.base_url=\"http://localhost:4010/v2\" \
        --config model_provider=\"mock_provider\" \
        --config model_providers.mock_provider.name="hello" \
        send-message-v2 "hello"`
    and verified that the mock_provider is called instead of default
    provider.
    
    #closes
    https://linear.app/openai/issue/CODEX-3956/config-flags-not-respected-in-codex-app-server
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • feat(app-server): thread/rollback API (#8454)
    Add `thread/rollback` to app-server to support IDEs undo-ing the last N
    turns of a thread.
    
    For context, an IDE partner will be supporting an "undo" capability
    where the IDE (the app-server client) will be responsible for reverting
    the local changes made during the last turn. To support this well, we
    also need a way to drop the last turn (or more generally, the last N
    turns) from the agent's context. This is what `thread/rollback` does.
    
    **Core idea**: A Thread rollback is represented as a persisted event
    message (EventMsg::ThreadRollback) in the rollout JSONL file, not by
    rewriting history. On resume, both the model's context (core replay) and
    the UI turn list (app-server v2's thread history builder) apply these
    markers so the pruned history is consistent across live conversations
    and `thread/resume`.
    
    Implementation notes:
    - Rollback only affects agent context and appends to the rollout file;
    clients are responsible for reverting files on disk.
    - If a thread rollback is currently in progress, subsequent
    `thread/rollback` calls are rejected.
    - Because we use `CodexConversation::submit` and codex core tracks
    active turns, returning an error on concurrent rollbacks is communicated
    via an `EventMsg::Error` with a new variant
    `CodexErrorInfo::ThreadRollbackFailed`. app-server watches for that and
    sends the BAD_REQUEST RPC response.
    
    Tests cover thread rollbacks in both core and app-server, including when
    `num_turns` > existing turns (which clears all turns).
    
    **Note**: this explicitly does **not** behave like `/undo` which we just
    removed from the CLI, which does the opposite of what `thread/rollback`
    does. `/undo` reverts local changes via ghost commits/snapshots and does
    not modify the agent's context / conversation history.
  • Clear copy pill background and add snapshot test (#8777)
    ### Motivation
    - Fix a visual bug where transcript text could bleed through the
    on-screen copy "pill" overlay.
    - Ensure the copy affordance fully covers the underlying buffer so the
    pill background is solid and consistent with styling.
    - Document the approach in-code to make the background-clearing
    rationale explicit.
    
    ### Description
    - Clear the pill area before drawing by iterating `Rect::positions()`
    and calling `cell.set_symbol(" ")` and `cell.set_style(base_style)` in
    `render_copy_pill` in `transcript_copy_ui.rs`.
    - Added an explanatory comment for why the pill background is explicitly
    cleared.
    - Added a unit test `copy_pill_clears_background` and committed the
    corresponding snapshot file to validate the rendering behavior.
    
    ### Testing
    - Ran `just fmt` (formatting completed; non-blocking environment warning
    may appear).
    - Ran `just fix -p codex-tui2` to apply lints/fixes (completed). 
    - Ran `cargo test -p codex-tui2` and all tests passed (snapshot updated
    and tests succeeded).
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_695c9b23e9b8832997d5a457c4d83410)
  • feat: agent controller (#8783)
    Added an agent control plane that lets sessions spawn or message other
    conversations via `AgentControl`.
    
    `AgentBus` (core/src/agent/bus.rs) keeps track of the last known status
    of a conversation.
    
    ConversationManager now holds shared state behind an Arc so AgentControl
    keeps only a weak back-reference, the goal is just to avoid explicit
    cycle reference.
    
    Follow-ups:
    * Build a small tool in the TUI to be able to see every agent and send
    manual message to each of them
    * Handle approval requests in this TUI
    * Add tools to spawn/communicate between agents (see related design)
    * Define agent types
  • feat: forced tool tips (#8752)
    Force an announcement tooltip in the CLI. This query the gh repo on this
    [file](https://raw.githubusercontent.com/openai/codex/main/announcement_tip.toml)
    which contains announcements in TOML looking like this:
    ```
    # Example announcement tips for Codex TUI.
    # Each [[announcements]] entry is evaluated in order; the last matching one is shown.
    # Dates are UTC, formatted as YYYY-MM-DD. The from_date is inclusive and the to_date is exclusive.
    # version_regex matches against the CLI version (env!("CARGO_PKG_VERSION")); omit to apply to all versions.
    # target_app specify which app should display the announcement (cli, vsce, ...).
    
    [[announcements]]
    content = "Welcome to Codex! Check out the new onboarding flow."
    from_date = "2024-10-01"
    to_date = "2024-10-15"
    version_regex = "^0\\.0\\.0$"
    target_app = "cli"
    ``` 
    
    To make this efficient, the announcement is queried on a best effort
    basis at the launch of the CLI (no refresh made after this).
    This is done in an async way and we display the announcement (with 100%
    probability) iff the announcement is available, the cache is correctly
    warmed and there is a matching announcement (matching is recomputed for
    each new session).
  • chore: add model/list call to app-server-test-client (#8331)
    Allows us to run `cargo run -p codex-app-server-test-client --
    model-list` to return the list of models over app-server.
  • fix: update model examples to gpt-5.2 (#8566)
    The models are outdated and sometime get used by GPT when it to try
    delegate.
    
    I have read the CLA Document and I hereby sign the CLA
  • fix: fix readiness subscribe token wrap-around (#8770)
    Fixes ReadinessFlag::subscribe to avoid handing out token 0 or duplicate
    tokens on i32 wrap-around, adds regression tests, and prevents readiness
    gates from getting stuck waiting on an unmarkable or mis-authorized
    token.
  • fix: render cwd-relative paths in tui (#8771)
    Display paths relative to the cwd before checking git roots so view
    image tool calls keep project-local names in jj/no-.git workspaces.
  • tui2: stop baking streaming wraps; reflow agent markdown (#8761)
    Background
    Streaming assistant prose in tui2 was being rendered with viewport-width
    wrapping during streaming, then stored in history cells as already split
    `Line`s. Those width-derived breaks became indistinguishable from hard
    newlines, so the transcript could not "un-split" on resize. This also
    degraded copy/paste, since soft wraps looked like hard breaks.
    
    What changed
    - Introduce width-agnostic `MarkdownLogicalLine` output in
    `tui2/src/markdown_render.rs`, preserving markdown wrap semantics:
    initial/subsequent indents, per-line style, and a preformatted flag.
    - Update the streaming collector (`tui2/src/markdown_stream.rs`) to emit
    logical lines (newline-gated) and remove any captured viewport width.
    - Update streaming orchestration (`tui2/src/streaming/*`) to queue and
    emit logical lines, producing `AgentMessageCell::new_logical(...)`.
    - Make `AgentMessageCell` store logical lines and wrap at render time in
    `HistoryCell::transcript_lines_with_joiners(width)`, emitting joiners so
    copy/paste can join soft-wrap continuations correctly.
    
    Overlay deferral
    When an overlay is active, defer *cells* (not rendered `Vec<Line>`) and
    render them at overlay close time. This avoids baking width-derived
    wraps based on a stale width.
    
    Tests + docs
    - Add resize/reflow regression tests + snapshots for streamed agent
    output.
    - Expand module/API docs for the new logical-line streaming pipeline and
    clarify joiner semantics.
    - Align scrollback-related docs/comments with current tui2 behavior
    (main draw loop does not flush queued "history lines" to the terminal).
    
    More details
    See `codex-rs/tui2/docs/streaming_wrapping_design.md` for the full
    problem statement and solution approach, and
    `codex-rs/tui2/docs/tui_viewport_and_history.md` for viewport vs printed
    output behavior.
  • fix: accept whitespace-padded patch markers (#8746)
    Trim whitespace when validating '*** Begin Patch'/'*** End Patch'
    markers in codex-apply-patch so padded marker lines parse as intended,
    and add regression coverage (unit + fixture scenario); this avoids
    apply_patch failures when models include extra spacing. Tested with
    cargo test -p codex-apply-patch.
  • chore(apply-patch) additional scenarios (#8230)
    ## Summary
    More apply-patch scenarios
    
    ## Testing
    - [x] This pr only adds tests
  • Allow global exec flags after resume and fix CI codex build/timeout (#8440)
    **Motivation**
    - Bring `codex exec resume` to parity with top‑level flags so global
    options (git check bypass, json, model, sandbox toggles) work after the
    subcommand, including when outside a git repo.
    
    **Description**
    - Exec CLI: mark `--skip-git-repo-check`, `--json`, `--model`,
    `--full-auto`, and `--dangerously-bypass-approvals-and-sandbox` as
    global so they’re accepted after `resume`.
    - Tests: add `exec_resume_accepts_global_flags_after_subcommand` to
    verify those flags work when passed after `resume`.
    
    **Testing**
    - `just fmt`
    - `cargo test -p codex-exec` (pass; ran with elevated perms to allow
    network/port binds)
    - Manual: exercised `codex exec resume` with global flags after the
    subcommand to confirm behavior.
  • Use ConfigLayerStack for skills discovery. (#8497)
    Use ConfigLayerStack to get all folders while loading skills.
  • [device-auth] Update login instruction for headless environments. (#8753)
    We've seen reports that people who try to login on a remote/headless
    machine will open the login link on their own machine and got errors.
    Update the instructions to ask those users to use `codex login
    --device-auth` instead.
    
    <img width="1434" height="938" alt="CleanShot 2026-01-05 at 11 35 02@2x"
    src="https://github.com/user-attachments/assets/2b209953-6a42-4eb0-8b55-bb0733f2e373"
    />
  • feat: add justification arg to prefix_rule() in *.rules (#8751)
    Adds an optional `justification` parameter to the `prefix_rule()`
    execpolicy DSL so policy authors can attach human-readable rationale to
    a rule. That justification is propagated through parsing/matching and
    can be surfaced to the model (or approval UI) when a command is blocked
    or requires approval.
    
    When a command is rejected (or gated behind approval) due to policy, a
    generic message makes it hard for the model/user to understand what went
    wrong and what to do instead. Allowing policy authors to supply a short
    justification improves debuggability and helps guide the model toward
    compliant alternatives.
    
    Example:
    
    ```python
    prefix_rule(
        pattern = ["git", "push"],
        decision = "forbidden",
        justification = "pushing is blocked in this repo",
    )
    ```
    
    If Codex tried to run `git push origin main`, now the failure would
    include:
    
    ```
    `git push origin main` rejected: pushing is blocked in this repo
    ```
    
    whereas previously, all it was told was:
    
    ```
    execpolicy forbids this command
    ```
  • best effort to "hide" Sandbox users (#8492)
    The elevated sandbox creates two new Windows users - CodexSandboxOffline
    and CodexSandboxOnline. This is necessary, so this PR does all that it
    can to "hide" those users. It uses the registry plus directory flags (on
    their home directories) to get them to show up as little as possible.