Commit Graph

70 Commits

  • Add an operation to override current task context (#2431)
    - Added an operation to override current task context
    - Added a test to check that cache stays the same
  • [tools] Add apply_patch tool (#2303)
    ## Summary
    We've been seeing a number of issues and reports with our synthetic
    `apply_patch` tool, e.g. #802. Let's make this a real tool - in my
    anecdotal testing, it's critical for GPT-OSS models, but I'd like to
    make it the standard across GPT-5 and codex models as well.
    
    ## Testing
    - [x] Tested locally
    - [x] Integration test
  • Added allow-expect-in-tests / allow-unwrap-in-tests (#2328)
    This PR:
    * Added the clippy.toml to configure allowable expect / unwrap usage in
    tests
    * Removed as many expect/allow lines as possible from tests
    * moved a bunch of allows to expects where possible
    
    Note: in integration tests, non `#[test]` helper functions are not
    covered by this so we had to leave a few lingering `expect(expect_used`
    checks around
  • fix: run python_multiprocessing_lock_works integration test on Mac and Linux (#2318)
    The high-order bit on this PR is that it makes it so `sandbox.rs` tests
    both Mac and Linux, as we introduce a general
    `spawn_command_under_sandbox()` function with platform-specific
    implementations for testing.
    
    An important, and interesting, discovery in porting the test to Linux is
    that (for reasons cited in the code comments), `/dev/shm` has to be
    added to `writable_roots` on Linux in order for `multiprocessing.Lock`
    to work there. Granting write access to `/dev/shm` comes with some
    degree of risk, so we do not make this the default for Codex CLI.
    
    Piggybacking on top of #2317, this moves the
    `python_multiprocessing_lock_works` test yet again, moving
    `codex-rs/core/tests/sandbox.rs` to `codex-rs/exec/tests/sandbox.rs`
    because in `codex-rs/exec/tests` we can use `cargo_bin()` like so:
    
    ```
    let codex_linux_sandbox_exe = assert_cmd::cargo::cargo_bin("codex-exec");
    ```
    
    which is necessary so we can use `codex_linux_sandbox_exe` and therefore
    `spawn_command_under_linux_sandbox` in an integration test.
    
    This also moves `spawn_command_under_linux_sandbox()` out of `exec.rs`
    and into `landlock.rs`, which makes things more consistent with
    `seatbelt.rs` in `codex-core`.
    
    For reference, https://github.com/openai/codex/pull/1808 is the PR that
    made the change to Seatbelt to get this test to pass on Mac.
  • fix: move general sandbox tests to codex-rs/core/tests/sandbox.rs (#2317)
    Previous to this PR, `codex-rs/core/tests/sandbox.rs` contained
    integration tests that were specific to Seatbelt. This PR moves those
    tests to `codex-rs/core/src/seatbelt.rs` and designates
    `codex-rs/core/tests/sandbox.rs` to be used as the home for
    cross-platform (well, Mac and Linux...) sandbox tests.
    
    To start, this migrates
    `python_multiprocessing_lock_works_under_seatbelt()` from #1823 to the
    new `sandbox.rs` because this is the type of thing that should work on
    both Mac _and_ Linux, though I still need to do some work to clean up
    the test so it works on both platforms.
  • [context] Store context messages in rollouts (#2243)
    ## Summary
    Currently, we use request-time logic to determine the user_instructions
    and environment_context messages. This means that neither of these
    values can change over time as conversations go on. We want to add in
    additional details here, so we're migrating these to save these messages
    to the rollout file instead. This is simpler for the client, and allows
    us to append additional environment_context messages to each turn if we
    want
    
    ## Testing
    - [x] Integration test coverage
    - [x] Tested locally with a few turns, confirmed model could reference
    environment context and cached token metrics were reasonably high
  • chore: introduce ConversationManager as a clearinghouse for all conversations (#2240)
    This PR does two things because after I got deep into the first one I
    started pulling on the thread to the second:
    
    - Makes `ConversationManager` the place where all in-memory
    conversations are created and stored. Previously, `MessageProcessor` in
    the `codex-mcp-server` crate was doing this via its `session_map`, but
    this is something that should be done in `codex-core`.
    - It unwinds the `ctrl_c: tokio::sync::Notify` that was threaded
    throughout our code. I think this made sense at one time, but now that
    we handle Ctrl-C within the TUI and have a proper `Op::Interrupt` event,
    I don't think this was quite right, so I removed it. For `codex exec`
    and `codex proto`, we now use `tokio::signal::ctrl_c()` directly, but we
    no longer make `Notify` a field of `Codex` or `CodexConversation`.
    
    Changes of note:
    
    - Adds the files `conversation_manager.rs` and `codex_conversation.rs`
    to `codex-core`.
    - `Codex` and `CodexSpawnOk` are no longer exported from `codex-core`:
    other crates must use `CodexConversation` instead (which is created via
    `ConversationManager`).
    - `core/src/codex_wrapper.rs` has been deleted in favor of
    `ConversationManager`.
    - `ConversationManager::new_conversation()` returns `NewConversation`,
    which is in line with the `new_conversation` tool we want to add to the
    MCP server. Note `NewConversation` includes `SessionConfiguredEvent`, so
    we eliminate checks in cases like `codex-rs/core/tests/client.rs` to
    verify `SessionConfiguredEvent` is the first event because that is now
    internal to `ConversationManager`.
    - Quite a bit of code was deleted from
    `codex-rs/mcp-server/src/message_processor.rs` since it no longer has to
    manage multiple conversations itself: it goes through
    `ConversationManager` instead.
    - `core/tests/live_agent.rs` has been deleted because I had to update a
    bunch of tests and all the tests in here were ignored, and I don't think
    anyone ever ran them, so this was just technical debt, at this point.
    - Removed `notify_on_sigint()` from `util.rs` (and in a follow-up, I
    hope to refactor the blandly-named `util.rs` into more descriptive
    files).
    - In general, I started replacing local variables named `codex` as
    `conversation`, where appropriate, though admittedly I didn't do it
    through all the integration tests because that would have added a lot of
    noise to this PR.
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2240).
    * #2264
    * #2263
    * __->__ #2240
  • 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.
  • [prompts] integration test prompt caching (#2189)
    ## Summary
    Our current approach to prompt caching is fragile! The current approach
    works, but we are planning to update to a more resilient system (storing
    them in the rollout file). Let's start adding some integration tests to
    ensure stability while we migrate it.
    
    ## Testing
    - [x] These are the tests 😎
  • Include output truncation message in tool call results (#2183)
    To avoid model being confused about incomplete output.
  • [core] Allow resume after client errors (#2053)
    ## Summary
    Allow tui conversations to resume after the client fails out of retries.
    I tested this with exec / mocked api failures as well, and it appears to
    be fine. But happy to add an exec integration test as well!
    
    ## Testing
    - [x] Added integration test
    - [x] Tested locally
  • chore: change CodexAuth::from_api_key() to take &str instead of String (#1970)
    Good practice and simplifies some of the call sites.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/1970).
    * #1971
    * __->__ #1970
    * #1966
    * #1965
    * #1962
  • chore: rename CodexAuth::new() to create_dummy_codex_auth_for_testing() because it is not for general consumption (#1962)
    `CodexAuth::new()` was the first method listed in `CodexAuth`, but it is
    only meant to be used by tests. Rename it to
    `create_dummy_chatgpt_auth_for_testing()` and move it to the end of the
    implementation.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/1962).
    * #1971
    * #1970
    * #1966
    * #1965
    * __->__ #1962
  • feat: parse info from auth.json and show in /status (#1923)
    - `/status` renders
        ```
        signed in with chatgpt
          login: example@example.com
          plan: plus
        ```
    - Setup for using this info in a few more places.
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • feat: add /tmp by default (#1919)
    Replaces the `include_default_writable_roots` option on
    `sandbox_workspace_write` (that defaulted to `true`, which was slightly
    weird/annoying) with `exclude_tmpdir_env_var`, which defaults to
    `false`.
    
    Though perhaps more importantly `/tmp` is now enabled by default as part
    of `sandbox_mode = "workspace-write"`, though `exclude_slash_tmp =
    false` can be used to disable this.
  • Prefer env var auth over default codex auth (#1861)
    ## Summary
    - Prioritize provider-specific API keys over default Codex auth when
    building requests
    - Add test to ensure provider env var auth overrides default auth
    
    ## Testing
    - `just fmt`
    - `just fix` *(fails: `let` expressions in this position are unstable)*
    - `cargo test --all-features` *(fails: `let` expressions in this
    position are unstable)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68926a104f7483208f2c8fd36763e0e3
  • [prompts] Add <environment_context> (#1869)
    ## Summary
    Includes a new user message in the api payload which provides useful
    environment context for the model, so it knows about things like the
    current working directory and the sandbox.
    
    ## Testing
    Updated unit tests
  • [approval_policy] Add OnRequest approval_policy (#1865)
    ## Summary
    A split-up PR of #1763 , stacked on top of a tools refactor #1858 to
    make the change clearer. From the previous summary:
    
    > Let's try something new: tell the model about the sandbox, and let it
    decide when it will need to break the sandbox. Some local testing
    suggests that it works pretty well with zero iteration on the prompt!
    
    ## Testing
    - [x] Added unit tests
    - [x] Tested locally and it appears to work smoothly!
  • [prompts] Better user_instructions handling (#1836)
    ## Summary
    Our recent change in #1737 can sometimes lead to the model confusing
    AGENTS.md context as part of the message. But a little prompting and
    formatting can help fix this!
    
    ## Testing
    - Ran locally with a few different prompts to verify the model
    behaves well.
    - Updated unit tests
  • [sandbox] Filter out certain non-sandbox errors (#1804)
    ## Summary
    Users frequently complain about re-approving commands that have failed
    for non-sandbox reasons. We can't diagnose with complete accuracy which
    errors happened because of a sandbox failure, but we can start to
    eliminate some common simple cases.
    
    This PR captures the most common case I've seen, which is a `command not
    found` error.
    
    ## Testing
    - [x] Added unit tests
    - [x] Ran a few cases locally
  • fix command duration display (#1806)
    we were always displaying "0ms" before.
    
    <img width="731" height="101" alt="Screenshot 2025-08-02 at 10 51 22 PM"
    src="https://github.com/user-attachments/assets/f56814ed-b9a4-4164-9e78-181c60ce19b7"
    />
  • feat: make .git read-only within a writable root when using Seatbelt (#1765)
    To make `--full-auto` safer, this PR updates the Seatbelt policy so that
    a `SandboxPolicy` with a `writable_root` that contains a `.git/`
    _directory_ will make `.git/` _read-only_ (though as a follow-up, we
    should also consider the case where `.git` is a _file_ with a `gitdir:
    /path/to/actual/repo/.git` entry that should also be protected).
    
    The two major changes in this PR:
    
    - Updating `SandboxPolicy::get_writable_roots_with_cwd()` to return a
    `Vec<WritableRoot>` instead of a `Vec<PathBuf>` where a `WritableRoot`
    can specify a list of read-only subpaths.
    - Updating `create_seatbelt_command_args()` to honor the read-only
    subpaths in `WritableRoot`.
    
    The logic to update the policy is a fairly straightforward update to
    `create_seatbelt_command_args()`, but perhaps the more interesting part
    of this PR is the introduction of an integration test in
    `tests/sandbox.rs`. Leveraging the new API in #1785, we test
    `SandboxPolicy` under various conditions, including ones where `$TMPDIR`
    is not readable, which is critical for verifying the new behavior.
    
    To ensure that Codex can run its own tests, e.g.:
    
    ```
    just codex debug seatbelt --full-auto -- cargo test if_git_repo_is_writable_root_then_dot_git_folder_is_read_only
    ```
    
    I had to introduce the use of `CODEX_SANDBOX=sandbox`, which is
    comparable to how `CODEX_SANDBOX_NETWORK_DISABLED=1` was already being
    used.
    
    Adding a comparable change for Landlock will be done in a subsequent PR.
  • feat: stream exec stdout events (#1786)
    ## Summary
    - stream command stdout as `ExecCommandStdout` events
    - forward streamed stdout to clients and ignore in human output
    processor
    - adjust call sites for new streaming API
  • Add /compact (#1527)
    - Add operation to summarize the context so far.
    - The operation runs a compact task that summarizes the context.
    - The operation clear the previous context to free the context window
    - The operation didn't use `run_task` to avoid corrupting the session
    - Add /compact in the tui
    
    
    
    https://github.com/user-attachments/assets/e06c24e5-dcfb-4806-934a-564d425a919c
  • Send account id when available (#1767)
    For users with multiple accounts we need to specify the account to use.
  • chore: refactor exec.rs: create separate seatbelt.rs and spawn.rs files (#1762)
    At 550 lines, `exec.rs` was a bit large. In particular, I found it hard
    to locate the Seatbelt-related code quickly without a file with
    `seatbelt` in the name, so this refactors things so:
    
    - `spawn_command_under_seatbelt()` and dependent code moves to a new
    `seatbelt.rs` file
    - `spawn_child_async()` and dependent code moves to a new `spawn.rs`
    file
  • Add codex login --api-key (#1759)
    Allow setting the API key via `codex login --api-key`
  • fix git tests (#1747)
    the git tests were failing on my local machine due to gpg signing config
    in my ~/.gitconfig. tests should not be affected by ~/.gitconfig, so
    configure them to ignore it.
  • Add support for a separate chatgpt auth endpoint (#1712)
    Adds a `CodexAuth` type that encapsulates information about available
    auth modes and logic for refreshing the token.
    Changes `Responses` API to send requests to different endpoints based on
    the auth type.
    Updates login_with_chatgpt to support API-less mode and skip the key
    exchange.
  • Relative instruction file (#1722)
    Passing in an instruction file with a bad path led to silent failures,
    also instruction relative paths were handled in an unintuitive fashion.
  • chore: update Codex::spawn() to return a struct instead of a tuple (#1677)
    Also update `init_codex()` to return a `struct` instead of a tuple, as well.
  • fix: create separate test_support crates to eliminate #[allow(dead_code)] (#1667)
    Because of a quirk of how implementation tests work in Rust, we had a
    number of `#[allow(dead_code)]` annotations that were misleading because
    the functions _were_ being used, just not by all integration tests in a
    `tests/` folder, so when compiling the test that did not use the
    function, clippy would complain that it was unused.
    
    This fixes things by create a "test_support" crate under the `tests/`
    folder that is imported as a dev dependency for the respective crate.
  • Record Git metadata to rollout (#1598)
    # Summary
    
    - Writing effective evals for codex sessions requires context of the
    overall repository state at the moment the session began
    - This change adds this metadata (git repository, branch, commit hash)
    to the top of the rollout of the session (if available - if not it
    doesn't add anything)
    - Currently, this is only effective on a clean working tree, as we can't
    track uncommitted/untracked changes with the current metadata set.
    Ideally in the future we may want to track unclean changes somehow, or
    perhaps prompt the user to stash or commit them.
    
    # Testing
    - Added unit tests
    - `cargo test && cargo clippy --tests && cargo fmt -- --config
    imports_granularity=Item`
    
    ### Resulting Rollout
    <img width="1243" height="127" alt="Screenshot 2025-07-17 at 1 50 00 PM"
    src="https://github.com/user-attachments/assets/68108941-f015-45b2-985c-ea315ce05415"
    />
  • Always send entire request context (#1641)
    Always store the entire conversation history.
    Request encrypted COT when not storing Responses.
    Send entire input context instead of sending previous_response_id
  • Add support for custom base instructions (#1645)
    Allows providing custom instructions file as a config parameter and
    custom instruction text via MCP tool call.
  • [mcp-server] Add reply tool call (#1643)
    ## Summary
    Adds a new mcp tool call, `codex-reply`, so we can continue existing
    sessions. This is a first draft and does not yet support sessions from
    previous processes.
    
    ## Testing
    - [x] tested with mcp client
  • Add session loading support to Codex (#1602)
    ## Summary
    - extend rollout format to store all session data in JSON
    - add resume/write helpers for rollouts
    - track session state after each conversation
    - support `LoadSession` op to resume a previous rollout
    - allow starting Codex with an existing session via
    `experimental_resume` config variable
    
    We need a way later for exploring the available sessions in a user
    friendly way.
    
    ## Testing
    - `cargo test --no-run` *(fails: `cargo: command not found`)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68792a29dd5c832190bf6930d3466fba
    
    This video is outdated. you should use `-c experimental_resume:<full
    path>` instead of `--resume <full path>`
    
    
    https://github.com/user-attachments/assets/7a9975c7-aa04-4f4e-899a-9e87defd947a
  • Refactor env settings into config (#1601)
    ## Summary
    - add OpenAI retry and timeout fields to Config
    - inject these settings in tests instead of mutating env vars
    - plumb Config values through client and chat completions logic
    - document new configuration options
    
    ## Testing
    - `cargo test -p codex-core --no-run`
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68792c5b04cc832195c03050c8b6ea94
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • feat: ensure session ID header is sent in Response API request (#1614)
    Include the current session id in Responses API requests.
  • Storing the sessions in a more organized way for easier look up. (#1596)
    now storing the sessions in `~/.codex/sessions/YYYY/MM/DD/<file>`
  • support deltas in core (#1587)
    - Added support for message and reasoning deltas
    - Skipped adding the support in the cli and tui for later
    - Commented a failing test (wrong merge) that needs fix in a separate
    PR.
    
    Side note: I think we need to disable merge when the CI don't pass.
  • Add CLI streaming integration tests (#1542)
    ## Summary
    - add integration test for chat mode streaming via CLI using wiremock
    - add integration test for Responses API streaming via fixture
    - call `cargo run` to invoke the CLI during tests
    
    ## Testing
    - `cargo test -p codex-core --test cli_stream -- --nocapture`
    - `cargo clippy --all-targets --all-features -- -D warnings`
    
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68715980bbec8321999534fdd6a013c1
  • Allow deadcode in test_support (#1555)
    #1546 Was pushed while not passing the clippy integration tests. This is
    fixing it.
  • Improve SSE tests (#1546)
    ## Summary
    - support fixture-based SSE data in tests
    - add helpers to load SSE JSON fixtures
    - add table-driven SSE unit tests
    - let integration tests use fixture loading
    - fix clippy errors from format! calls
    
    ## Testing
    - `cargo clippy --tests`
    - `cargo test --workspace --exclude codex-linux-sandbox`
    
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68717468c3e48321b51c9ecac6ba0f09