Commit Graph

453 Commits

  • feat: change the behavior of SetDefaultModel RPC so None clears the value. (#3529)
    It turns out that we want slightly different behavior for the
    `SetDefaultModel` RPC because some models do not work with reasoning
    (like GPT-4.1), so we should be able to explicitly clear this value.
    
    Verified in `codex-rs/mcp-server/tests/suite/set_default_model.rs`.
  • standardize shell description (#3514)
    ## Summary
    Standardizes the shell description across sandbox_types, since we cover
    this in the prompt, and have moved necessary details (like
    network_access and writeable workspace roots) to EnvironmentContext
    messages.
    
    ## Test Plan
    - [x] updated unit tests
  • bug: fix model save (#3525)
    Fix those 2 behaviors:
    1. The model does not get saved if we don't CTRL + S
    2. The reasoning effort get saved
  • feat: added SetDefaultModel to JSON-RPC server (#3512)
    This adds `SetDefaultModel`, which takes `model` and `reasoning_effort`
    as optional fields. If set, the field will overwrite what is in the
    user's `config.toml`.
    
    This reuses logic that was added to support the `/model` command in the
    TUI: https://github.com/openai/codex/pull/2799.
  • feat: include reasoning_effort in NewConversationResponse (#3506)
    `ClientRequest::NewConversation` picks up the reasoning level from the user's defaults in `config.toml`, so it should be reported in `NewConversationResponse`.
  • Log cf-ray header in client traces (#3488)
    ## Summary
    - log the `cf-ray` header when tracing HTTP responses in the Codex
    client
    - keep existing response status logging unchanged
    
    ## Testing
    - just fmt
    - just fix -p codex-core
    - cargo test -p codex-core *(fails:
    suite::client::azure_overrides_assign_properties_used_for_responses_url,
    suite::client::env_var_overrides_loaded_auth)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68c31640dacc83209be131baf91611cd
  • bug: default to image (#3501)
    Default the MIME type to image
  • feat: TUI onboarding (#3398)
    Example of how onboarding could look like
  • Use PlanType enum when formatting usage-limit CTA (#3495)
    - Started using Play type struct
    - Added CTA for team/business 
    - Refactored a bit to unify the logic
  • fix: improve handle_sandbox_error timeouts (#3435)
    ## Summary
    Handle timeouts the same way, regardless of approval mode. There's more
    to do here, but this is simple and should be zero-regret
    
    ## Testing
    - [x] existing tests pass
    - [x] test locally and verify rollout
  • chore: enable clippy::redundant_clone (#3489)
    Created this PR by:
    
    - adding `redundant_clone` to `[workspace.lints.clippy]` in
    `cargo-rs/Cargol.toml`
    - running `cargo clippy --tests --fix`
    - running `just fmt`
    
    Though I had to clean up one instance of the following that resulted:
    
    ```rust
    let codex = codex;
    ```
  • Assign the entire gpt-5 model family same characteristics (#3490)
    So the context size indicator is displayed.
  • Add Compact and Turn Context to the rollout items (#3444)
    Adding compact and turn context to the rollout items
    
    based on #3440
  • NIT unified exec (#3479)
    Fix the default value of the experimental flag of unified_exec
  • Simplify auth flow and reconcile differences between ChatGPT and API Key auth (#3189)
    This PR does the following:
    * Adds the ability to paste or type an API key.
    * Removes the `preferred_auth_method` config option. The last login
    method is always persisted in auth.json, so this isn't needed.
    * If OPENAI_API_KEY env variable is defined, the value is used to
    prepopulate the new UI. The env variable is otherwise ignored by the
    CLI.
    * Adds a new MCP server entry point "login_api_key" so we can implement
    this same API key behavior for the VS Code extension.
    <img width="473" height="140" alt="Screenshot 2025-09-04 at 3 51 04 PM"
    src="https://github.com/user-attachments/assets/c11bbd5b-8a4d-4d71-90fd-34130460f9d9"
    />
    <img width="726" height="254" alt="Screenshot 2025-09-04 at 3 51 32 PM"
    src="https://github.com/user-attachments/assets/6cc76b34-309a-4387-acbc-15ee5c756db9"
    />
  • Change forking to read the rollout from file (#3440)
    This PR changes get history op to get path. Then, forking will use a
    path. This will help us have one unified codepath for resuming/forking
    conversations. Will also help in having rollout history in order. It
    also fixes a bug where you won't see the UI when resuming after forking.
  • Unified execution (#3288)
    ## Unified PTY-Based Exec Tool
    
    Note: this requires to have this flag in the config:
    `use_experimental_unified_exec_tool=true`
    
    - Adds a PTY-backed interactive exec feature (“unified_exec”) with
    session reuse via
      session_id, bounded output (128 KiB), and timeout clamping (≤ 60 s).
    - Protocol: introduces ResponseItem::UnifiedExec { session_id,
    arguments, timeout_ms }.
    - Tools: exposes unified_exec as a function tool (Responses API);
    excluded from Chat
      Completions payload while still supported in tool lists.
    - Path handling: resolves commands via PATH (or explicit paths), with
    UTF‑8/newline‑aware
      truncation (truncate_middle).
    - Tests: cover command parsing, path resolution, session
    persistence/cleanup, multi‑session
      isolation, timeouts, and truncation behavior.
  • fix: ensure output of codex-rs/mcp-types/generate_mcp_types.py matches codex-rs/mcp-types/src/lib.rs (#3439)
    https://github.com/openai/codex/pull/3395 updated `mcp-types/src/lib.rs`
    by hand, but that file is generated code that is produced by
    `mcp-types/generate_mcp_types.py`. Unfortunately, we do not have
    anything in CI to verify this right now, but I will address that in a
    subsequent PR.
    
    #3395 ended up introducing a change that added a required field when
    deserializing `InitializeResult`, breaking Codex when used as an MCP
    client, so the quick fix in #3436 was to make the new field `Optional`
    with `skip_serializing_if = "Option::is_none"`, but that did not address
    the problem that `mcp-types/generate_mcp_types.py` and
    `mcp-types/src/lib.rs` are out of sync.
    
    This PR gets things back to where they are in sync. It removes the
    custom `mcp_types::McpClientInfo` type that was added to
    `mcp-types/src/lib.rs` and forces us to use the generated
    `mcp_types::Implementation` type. Though this PR also updates
    `generate_mcp_types.py` to generate the additional `user_agent:
    Optional<String>` field on `Implementation` so that we can continue to
    specify it when Codex operates as an MCP server.
    
    However, this also requires us to specify `user_agent: None` when Codex
    operates as an MCP client.
    
    We may want to introduce our own `InitializeResult` type that is
    specific to when we run as a server to avoid this in the future, but my
    immediate goal is just to get things back in sync.
  • fix trampling projects table when accepting trusted dirs (#3434)
    Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
  • put workspace roots in the environment context (#3375)
    to keep the tool description constant when the writable roots change.
  • Persist model & reasoning changes (#2799)
    Persists `/model` changes across both general and profile-specific
    sessions.
  • Back out "feat: POSIX unification and snapshot sessions (#3179)" (#3430)
    This reverts https://github.com/openai/codex/pull/3179.
    
    #3179 appears to introduce a regression where sourcing dotfiles causes a
    bunch of activity in the title bar (and potentially slows things down?)
    
    
    https://github.com/user-attachments/assets/a68f7fb3-0749-4e0e-a321-2aa6993e01da
    
    Verified this no longer happens after backing out #3179.
    
    Original commit changeset: 62bd0e3d9d
  • Added images to UserMessageEvent (#3400)
    This PR adds an `images` field to the existing `UserMessageEvent` so we
    can encode zero or more images associated with a user message. This
    allows images to be restored when conversations are restored.
  • Move initial history to protocol (#3422)
    To fix an edge case of forking then resuming
    
    #3419
  • Set a user agent suffix when used as a mcp server (#3395)
    This automatically adds a user agent suffix whenever the CLI is used as
    a MCP server
  • Introduce rollout items (#3380)
    This PR introduces Rollout items. This enable us to rollout eventmsgs
    and session meta.
    
    This is mostly #3214 with rebase on main
  • Include apply_patch tool for oss models from gpt-oss providers with different naming convention (e.g. openai/gpt-oss-*) (#2811)
    Model providers like Groq, Openrouter, AWS Bedrock, VertexAI and others
    typically prefix the name of gpt-oss models with `openai`, e.g.
    `openai/gpt-oss-120b`.
    
    This PR is to match the model name slug using `contains` instead of
    `starts_with` to ensure that the `apply_patch` tool is included in the
    tools for models names like `openai/gpt-oss-120b`
    
    Without this, the gpt-oss models will often try to call the
    `apply_patch` tool directly instead of via the `shell` command, leading
    to validation errors.
    
    I have run all the local checks.
    
    Note: The gpt-oss models from non-Ollama providers are typically run via
    a profile with a different base_url (instead of with the `--oss` flag)
    
    ---------
    
    Co-authored-by: Andrew Tan <andrewtan@Andrews-Mac.local>
  • Replace config.responses_originator_header_internal_override with CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR (#3388)
    The previous config approach had a few issues:
    1. It is part of the config but not designed to be used externally
    2. It had to be wired through many places (look at the +/- on this PR
    3. It wasn't guaranteed to be set consistently everywhere because we
    don't have a super well defined way that configs stack. For example, the
    extension would configure during newConversation but anything that
    happened outside of that (like login) wouldn't get it.
    
    This env var approach is cleaner and also creates one less thing we have
    to deal with when coming up with a better holistic story around configs.
    
    One downside is that I removed the unit test testing for the override
    because I don't want to deal with setting the global env or spawning
    child processes and figuring out how to introspect their originator
    header. The new code is sufficiently simple and I tested it e2e that I
    feel as if this is still worth it.
  • feat(core): re-export InitialHistory from conversation_manager (#3270)
    This commit adds a re-export for InitialHistory from the internal
    conversation_manager module in codex-core's lib.rs.
    
    The `RolloutRecorder::get_rollout_history` method (exposed via `pub use
    rollout::RolloutRecorder;`, already present in lib.rs) returns an
    `InitialHistory` type, which is defined in the private
    conversation_manager module. Without this re-export, consumers of the
    public RolloutRecorder API would not be able to directly use the return
    type, as they cannot access the private module. This would result in an
    inconvenient experience where the method's return value cannot be
    handled without additional, non-obvious imports.
    
    By adding `pub use conversation_manager::InitialHistory;`, we make
    InitialHistory available as `codex_core::InitialHistory`, improving API
    ergonomics for users of the rollout functionality while keeping the
    conversation_manager module internal.
    
    No functional changes are made; this is a pure re-export for better
    usability.
    
    Signed-off-by: M4n5ter <m4n5terrr@gmail.com>
  • feat: add ArchiveConversation to ClientRequest (#3353)
    Adds support for `ArchiveConversation` in the JSON-RPC server that takes
    a `(ConversationId, PathBuf)` pair and:
    
    - verifies the `ConversationId` corresponds to the rollout id at the
    `PathBuf`
    - if so, invokes
    `ConversationManager.remove_conversation(ConversationId)`
    - if the `CodexConversation` was in memory, send `Shutdown` and wait for
    `ShutdownComplete` with a timeout
    - moves the `.jsonl` file to `$CODEX_HOME/archived_sessions`
    
    ---------
    
    Co-authored-by: Gabriel Peal <gabriel@openai.com>
  • fix: include rollout_path in NewConversationResponse (#3352)
    Adding the `rollout_path` to the `NewConversationResponse` makes it so a
    client can perform subsequent operations on a `(ConversationId,
    PathBuf)` pair. #3353 will introduce support for `ArchiveConversation`.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/3352).
    * #3353
    * __->__ #3352
  • feat: POSIX unification and snapshot sessions (#3179)
    ## Session snapshot
    For POSIX shell, the goal is to take a snapshot of the interactive shell
    environment, store it in a session file located in `.codex/` and only
    source this file for every command that is run.
    As a result, if a snapshot files exist, `bash -lc <CALL>` get replaced
    by `bash -c <CALL>`.
    
    This also fixes the issue that `bash -lc` does not source `.bashrc`,
    resulting in missing env variables and aliases in the codex session.
    ## POSIX unification
    Unify `bash` and `zsh` shell into a POSIX shell. The rational is that
    the tool will not use any `zsh` specific capabilities.
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • Generate more typescript types and return conversation id with ConversationSummary (#3219)
    This PR does multiple things that are necessary for conversation resume
    to work from the extension. I wanted to make sure everything worked so
    these changes wound up in one PR:
    1. Generate more ts types
    2. Resume rollout history files rather than create a new one every time
    it is resumed so you don't see a duplicate conversation in history for
    every resume. Chatted with @aibrahim-oai to verify this
    3. Return conversation_id in conversation summaries
    4. [Cleanup] Use serde and strong types for a lot of the rollout file
    parsing
  • fix: improve MCP server initialization error handling #3196 #2346 #2555 (#3243)
    • I have signed the CLA by commenting the required sentence and
    triggered recheck.
    • Local checks are all green (fmt / clippy / test).
    • Could you please approve the pending GitHub Actions workflows
    (first-time contributor), and when convenient, help with one approving
    review so I can proceed? Thanks!
    
      ## Summary
    - Catch and log task panics during server initialization instead of
    propagating JoinError
    - Handle tool listing failures gracefully, allowing partial server
    initialization
    - Improve error resilience on macOS where init timeouts are more common
    
      ## Test plan
      - [x] Test MCP server initialization with timeout scenarios
      - [x] Verify graceful handling of tool listing failures
      - [x] Confirm improved error messages and logging
      - [x] Test on macOS 
    
     ## Fix issue  #3196 #2346 #2555
    ### fix before:
    <img width="851" height="363" alt="image"
    src="https://github.com/user-attachments/assets/e1f9c749-71fd-4873-a04f-d3fc4cbe0ae6"
    />
    
    <img width="775" height="108" alt="image"
    src="https://github.com/user-attachments/assets/4e4748bd-9dd6-42b5-b38b-8bfe9341a441"
    />
    
    ### fix improved:
    <img width="966" height="528" alt="image"
    src="https://github.com/user-attachments/assets/418324f3-e37a-4a3c-8bdd-934f9ff21dfb"
    />
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • feat(mcp): per-server startup timeout (#3182)
    Seeing timeouts on certain, slow mcp server starting up when codex is
    invoked. Before this change, the timeout was a hard-coded 10s. Need the
    ability to define arbitrary timeouts on a per-server basis.
    
    ## Summary of changes
    
    - Add startup_timeout_ms to McpServerConfig with 10s default when unset
    - Use per-server timeout for initialize and tools/list
    - Introduce ManagedClient to store client and timeout; rename
    LIST_TOOLS_TIMEOUT to DEFAULT_STARTUP_TIMEOUT
    - Update docs to document startup_timeout_ms with example and options
    table
    
    ---------
    
    Co-authored-by: Matthew Dolan <dolan-openai@users.noreply.github.com>
  • Use ConversationId instead of raw Uuids (#3282)
    We're trying to migrate from `session_id: Uuid` to `conversation_id:
    ConversationId`. Not only does this give us more type safety but it
    unifies our terminology across Codex and with the implementation of
    session resuming, a conversation (which can span multiple sessions) is
    more appropriate.
    
    I started this impl on https://github.com/openai/codex/pull/3219 as part
    of getting resume working in the extension but it's big enough that it
    should be broken out.
  • Move token usage/context information to session level (#3221)
    Move context information into the main loop so it can be used to
    interrupt the loop or start auto-compaction.
  • 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.
  • 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.
  • [mcp-server] Update read config interface (#3093)
    ## Summary
    Follow-up to #3056
    
    This PR updates the mcp-server interface for reading the config settings
    saved by the user. At risk of introducing _another_ Config struct, I
    think it makes sense to avoid tying our protocol to ConfigToml, as its
    become a bit unwieldy. GetConfigTomlResponse was a de-facto struct for
    this already - better to make it explicit, in my opinion.
    
    This is technically a breaking change of the mcp-server protocol, but
    given the previous interface was introduced so recently in #2725, and we
    have not yet even started to call it, I propose proceeding with the
    breaking change - but am open to preserving the old endpoint.
    
    ## Testing
    - [x] Added additional integration test coverage
  • fix: use a more efficient wire format for ExecCommandOutputDeltaEvent.chunk (#3163)
    When serializing to JSON, the existing solution created an enormous
    array of ints, which is far more bytes on the wire than a base64-encoded
    string would be.
  • fix: add callback to map before sending request to fix race condition (#3146)
    Last week, I thought I found the smoking gun in our flaky integration
    tests where holding these locks could have led to potential deadlock:
    
    - https://github.com/openai/codex/pull/2876
    - https://github.com/openai/codex/pull/2878
    
    Yet even after those PRs went in, we continued to see flakinees in our
    integration tests! Though with the additional logging added as part of
    debugging those tests, I now saw things like:
    
    ```
    read message from stdout: Notification(JSONRPCNotification { jsonrpc: "2.0", method: "codex/event/exec_approval_request", params: Some(Object {"id": String("0"), "msg": Object {"type": String("exec_approval_request"), "call_id": String("call1"), "command": Array [String("python3"), String("-c"), String("print(42)")], "cwd": String("/tmp/.tmpFj2zwi/workdir")}, "conversationId": String("c67b32c5-9475-41bf-8680-f4b4834ebcc6")}) })
    notification: Notification(JSONRPCNotification { jsonrpc: "2.0", method: "codex/event/exec_approval_request", params: Some(Object {"id": String("0"), "msg": Object {"type": String("exec_approval_request"), "call_id": String("call1"), "command": Array [String("python3"), String("-c"), String("print(42)")], "cwd": String("/tmp/.tmpFj2zwi/workdir")}, "conversationId": String("c67b32c5-9475-41bf-8680-f4b4834ebcc6")}) })
    read message from stdout: Request(JSONRPCRequest { id: Integer(0), jsonrpc: "2.0", method: "execCommandApproval", params: Some(Object {"conversation_id": String("c67b32c5-9475-41bf-8680-f4b4834ebcc6"), "call_id": String("call1"), "command": Array [String("python3"), String("-c"), String("print(42)")], "cwd": String("/tmp/.tmpFj2zwi/workdir")}) })
    writing message to stdin: Response(JSONRPCResponse { id: Integer(0), jsonrpc: "2.0", result: Object {"decision": String("approved")} })
    in read_stream_until_notification_message(codex/event/task_complete)
    [mcp stderr] 2025-09-04T00:00:59.738585Z  INFO codex_mcp_server::message_processor: <- response: JSONRPCResponse { id: Integer(0), jsonrpc: "2.0", result: Object {"decision": String("approved")} }
    [mcp stderr] 2025-09-04T00:00:59.738740Z DEBUG codex_core::codex: Submission sub=Submission { id: "1", op: ExecApproval { id: "0", decision: Approved } }
    [mcp stderr] 2025-09-04T00:00:59.738832Z  WARN codex_core::codex: No pending approval found for sub_id: 0
    ```
    
    That is, a response was sent for a request, but no callback was in place
    to handle the response!
    
    This time, I think I may have found the underlying issue (though the
    fixes for holding locks for too long may have also been part of it),
    which is I found cases where we were sending the request:
    
    
    https://github.com/openai/codex/blob/234c0a0469db222f05df08d00ae5032312f77427/codex-rs/core/src/codex.rs#L597
    
    before inserting the `Sender` into the `pending_approvals` map (which
    has to wait on acquiring a mutex):
    
    
    https://github.com/openai/codex/blob/234c0a0469db222f05df08d00ae5032312f77427/codex-rs/core/src/codex.rs#L598-L601
    
    so it is possible the request could go out and the client could respond
    before `pending_approvals` was updated!
    
    Note this was happening in both `request_command_approval()` and
    `request_patch_approval()`, which maps to the sorts of errors we have
    been seeing when these integration tests have been flaking on us.
    
    While here, I am also adding some extra logging that prints if inserting
    into `pending_approvals` overwrites an entry as opposed to purely
    inserting one. Today, a conversation can have only one pending request
    at a time, but as we are planning to support parallel tool calls, this
    invariant may not continue to hold, in which case we need to revisit
    this abstraction.
  • 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.