Commit Graph

1399 Commits

Author SHA1 Message Date
Alexander Smirnov
183fc8e01a core: replace Cloudflare 403 HTML with friendly message (#6252)
### Motivation

When Codex is launched from a region where Cloudflare blocks access (for
example, Russia), the CLI currently dumps Cloudflare’s entire HTML error
page. This isn’t actionable and makes it hard for users to understand
what happened. We want to detect the Cloudflare block and show a
concise, user-friendly explanation instead.

### What Changed

- Added CLOUDFLARE_BLOCKED_MESSAGE and a friendly_message() helper to
UnexpectedResponseError. Whenever we see a 403 whose body contains the
Cloudflare block notice, we now emit a single-line message (Access
blocked by Cloudflare…) while preserving the HTTP status and request id.
All other responses keep the original behaviour.
- Added two focused unit tests:
- unexpected_status_cloudflare_html_is_simplified ensures the Cloudflare
HTML case yields the friendly message.
- unexpected_status_non_html_is_unchanged confirms plain-text 403s still
return the raw body.

### Testing

- cargo build -p codex-cli
- cargo test -p codex-core
- just fix -p codex-core
- cargo test --all-features

---------

Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-07 15:55:16 -08:00
Josh McKinney
9fba811764 refactor(terminal): cleanup deprecated flush logic (#6373)
Removes flush logic that was leftover to test against ratatui's flush
Cleaned up the flush logic so it's a bit more intent revealing.
DrawCommand now owns the Cells that it draws as this works around a
borrow checker problem.
2025-11-07 15:54:07 -08:00
Celia Chen
db408b9e62 [App-server] add initialization to doc (#6377)
Address comments in #6353.
2025-11-07 23:52:20 +00:00
Jakob Malmo
2eecc1a2e4 fix(wsl): normalize Windows paths during update (#6086) (#6097)
When running under WSL, the update command could receive Windows-style
absolute paths (e.g., `C:\...`) and pass them to Linux processes
unchanged, which fails because WSL expects those paths in
`/mnt/<drive>/...` form.

This patch adds a tiny helper in the CLI (`cli/src/wsl_paths.rs`) that:
- Detects WSL (`WSL_DISTRO_NAME` or `"microsoft"` in `/proc/version`)  
- Converts `X:\...` → `/mnt/x/...`  

`run_update_action` now normalizes the package-manager command and
arguments under WSL before spawning.
Non-WSL platforms are unaffected.  

Includes small unit tests for the converter.  

**Fixes:** #6086, #6084

Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-07 14:49:17 -08:00
Michael Bolin
bb47f2226f feat: add --promote-alpha option to create_github_release script (#6370)
Historically, running `create_github_release --publish-release` would
always publish a new release from latest `main`, which isn't always the
best idea. We should really publish an alpha, let it bake, and then
promote it.

This PR introduces a new flag, `--promote-alpha`, which does exactly
that. It also works with `--dry-run`, so you can sanity check the commit
it will use as the base commit for the new release before running it for
real.

```shell
$ ./codex-rs/scripts/create_github_release --dry-run --promote-alpha 0.56.0-alpha.2
Publishing version 0.56.0
Running gh api GET /repos/openai/codex/git/refs/tags/rust-v0.56.0-alpha.2
Running gh api GET /repos/openai/codex/git/tags/7d4ef77bc35b011aa0c76c5cbe6cd7d3e53f1dfe
Running gh api GET /repos/openai/codex/compare/main...8b49211e67d3c863df5ecc13fc5f88516a20fa69
Would publish version 0.56.0 using base commit 62474a30e8 derived from rust-v0.56.0-alpha.2.
```
2025-11-07 20:05:22 +00:00
Jeremy Rose
c6ab92bc50 tui: add comments to tui.rs (#6369) 2025-11-07 18:17:52 +00:00
pakrym-oai
4c1a6f0ee0 Promote shell config tool to model family config (#6351) 2025-11-07 10:11:11 -08:00
Owen Lin
361d43b969 [app-server] doc: update README for threads and turns (#6368)
Self explanatory!
2025-11-07 17:02:49 +00:00
Celia Chen
2e81f1900d [App-server] Add auth v2 doc & update codex mcp interface auth section (#6353)
Added doc for auth v2 endpoints. Updated the auth section in Codex MCP
interface doc too.
2025-11-07 08:17:19 -08:00
Owen Lin
2030b28083 [app-server] feat: expose additional fields on Thread (#6338)
Add the following fields to Thread:

```
    pub preview: String,
    pub model_provider: String,
    pub created_at: i64,
```

Will prob need another PR once this lands:
https://github.com/openai/codex/pull/6337
2025-11-07 04:08:45 +00:00
Celia Chen
e84e39940b [App-server] Implement account/read endpoint (#6336)
This PR does two things:
1. add a new function in core that maps the core-internal plan type to
the external plan type;
2. implement account/read that get account status (v2 of
`getAuthStatus`).
2025-11-06 19:43:13 -08:00
pakrym-oai
e8905f6d20 Prefer wait_for_event over wait_for_event_with_timeout (#6349) 2025-11-06 18:11:11 -08:00
Shane Vitarana
316352be94 Fix apply_patch rename move path resolution (#5486)
Fixes https://github.com/openai/codex/issues/5485.

Fixed rename hunks so `apply_patch` resolves the destination path using
the verifier’s effective cwd, ensuring patches that run under `cd
<worktree> && apply_patch` stay inside the worktree.

Added a regression test
(`test_apply_patch_resolves_move_path_with_effective_cwd`) that
reproduced the old behavior (dest path resolved in the main repo) and
now passes.

Related to https://github.com/openai/codex/issues/5483.

Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-06 17:02:09 -08:00
pakrym-oai
f8b30af6dc Prefer wait_for_event over wait_for_event_with_timeout. (#6346)
No need to specify the timeout in most cases.
2025-11-06 16:14:43 -08:00
pakrym-oai
c368c6aeea Remove shell tool when unified exec is enabled (#6345)
Also drop streameable shell that's just an alias for unified exec.
2025-11-06 15:46:24 -08:00
Eric Traut
0c647bc566 Don't retry "insufficient_quota" errors (#6340)
This PR makes an "insufficient quota" error fatal so we don't attempt to
retry it multiple times in the agent loop.

We have multiple bug reports from users about intermittent retry
behaviors, and this could explain some of them. With this change, we'll
eliminate the retries and surface a clear error message.

The PR is a nearly identical copy of [this
PR](https://github.com/openai/codex/pull/4837) contributed by
@abimaelmartell. The original PR has gone stale. Rather than wait for
the contributor to resolve merge conflicts, I wanted to get this change
in.
2025-11-06 15:12:01 -08:00
Ejaz Ahmed
e30f65118d feat: Enable CTRL-n and CTRL-p for navigating slash commands, files, history (#1994)
Adds CTRL-n and CTRL-p navigation for slash commands, files, and
history.
Closes #1992

Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-06 14:58:18 -08:00
Jeremy Rose
1bd2d7a659 tui: fix backtracking past /status (#6335)
Fixes https://github.com/openai/codex/issues/4722

Supersedes https://github.com/openai/codex/pull/5058

Ideally we'd have a clearer way of separating history per-session than
by detecting a specific history cell type, but this is a fairly minimal
fix for now.
2025-11-06 14:50:07 -08:00
Gabriel Peal
65d53fd4b1 Make generate_ts prettier output warn-only (#6342)
Before, every file would be outputted with the time prettier spent
formatting it. This made downstream scripts way too noisy.
2025-11-06 17:45:51 -05:00
pakrym-oai
b5349202e9 Freeform unified exec output formatting (#6233) 2025-11-06 22:14:27 +00:00
Gabriel Peal
1b8cc8b625 [App Server] Add more session metadata to listConversations (#6337)
This unlocks a few new product experience for app server consumers
2025-11-06 17:13:24 -05:00
Jeremy Rose
8501b0b768 core: widen sandbox to allow certificate ops when network is enabled (#5980)
This allows `gh api` to work in the workspace-write sandbox w/ network
enabled. Without this we see e.g.

```
$ codex debug seatbelt --full-auto gh api repos/openai/codex/pulls --paginate -X GET -F state=all
Get "https://api.github.com/repos/openai/codex/pulls?per_page=100&state=all": tls: failed to verify certificate: x509: OSStatus -26276
```
2025-11-06 12:47:20 -08:00
Thibault Sottiaux
8c75ed39d5 feat: clarify that gpt-5-codex should not amend commits unless requested (#6333) 2025-11-06 11:42:47 -08:00
Owen Lin
fdb9fa301e chore: move relevant tests to app-server/tests/suite/v2 (#6289)
These are technically app-server v2 APIs, so move them to the same
directory as the others.
2025-11-06 10:53:17 -08:00
iceweasel-oai
871d442b8e Windows Sandbox: Show Everyone-writable directory warning (#6283)
Show a warning when Auto Sandbox mode becomes enabled, if we detect
Everyone-writable directories, since they cannot be protected by the
current implementation of the Sandbox.

This PR also includes changes to how we detect Everyone-writable to be
*much* faster
2025-11-06 10:44:42 -08:00
Ahmed Ibrahim
dbad5eeec6 chore: fix grammar mistakes (#6326) 2025-11-06 09:48:59 -08:00
Owen Lin
6582554926 [app-server] feat: v2 Turn APIs (#6216)
Implements:
```
turn/start
turn/interrupt
```

along with their integration tests. These are relatively light wrappers
around the existing core logic, and changes to core logic are minimal.

However, an improvement made for developer ergonomics:
- `turn/start` replaces both `SendUserMessage` (no turn overrides) and
`SendUserTurn` (can override model, approval policy, etc.)
2025-11-06 16:36:36 +00:00
Thibault Sottiaux
649ce520c4 chore: rename for clarity (#6319)
Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
2025-11-06 08:32:57 -08:00
Thibault Sottiaux
667e841d3e feat: support models with single reasoning effort (#6300) 2025-11-05 23:06:45 -08:00
Ahmed Ibrahim
63e1ef25af feat: add model nudge for queries (#6286) 2025-11-06 03:42:59 +00:00
Celia Chen
229d18f4d2 [App-server] Add account/login/cancel v2 endpoint (#6288)
Add `account/login/cancel` v2 endpoint for auth. this is similar
implementation to `cancelLoginChatgpt` v1 endpoint.
2025-11-06 01:13:55 +00:00
Eric Traut
86c149ae8e Prevent dismissal of login menu in TUI (#6285)
We currently allow the user to dismiss the login menu via Ctrl+C. This
leaves them in a bad state where they're not auth'ed but have an input
prompt. In the extension, this isn't a problem because we don't allow
the user to dismiss the login screen.

Testing: I confirmed that Ctrl+C no longer dismisses the login menu.

This is an alternative (simpler) fix for a [community
PR](https://github.com/openai/codex/pull/3234).
2025-11-05 14:25:58 -08:00
Celia Chen
05f0b4f590 [App-server] Implement v2 for account/login/start and account/login/completed (#6183)
This PR implements `account/login/start` and `account/login/completed`.
Instead of having separate endpoints for login with chatgpt and api, we
have a single enum handling different login methods. For sync auth
methods like sign in with api key, we still send a `completed`
notification back to be compatible with the async login flow.
2025-11-05 13:52:50 -08:00
easong-openai
d4eda9d10b stop capturing r when environment selection modal is open (#6249)
This fixes an issue where you can't select environments with an r in them when the selection modal is open
2025-11-05 13:23:46 -08:00
Eric Traut
d7953aed74 Fixes intermittent test failures in CI (#6282)
I'm seeing two tests fail intermittently in CI. This PR attempts to
address (or at least mitigate) the flakiness.

* summarize_context_three_requests_and_instructions - The test snapshots
server.received_requests() immediately after observing TaskComplete.
Because the OpenAI /v1/responses call is streamed, the HTTP request can
still be draining when that event fires, so wiremock occasionally
reports only two captured requests. Fix is to wait for async activity to
complete.
* archive_conversation_moves_rollout_into_archived_directory - times out
on a slow CI run. Mitigation is to increase timeout value from 10s to
20s.
2025-11-05 13:12:25 -08:00
Owen Lin
2ab1650d4d [app-server] feat: v2 Thread APIs (#6214)
Implements:
```
thread/list
thread/start
thread/resume
thread/archive
```

along with their integration tests. These are relatively light wrappers
around the existing core logic, and changes to core logic are minimal.

However, an improvement made for developer ergonomics:
- `thread/start` and `thread/resume` automatically attaches a
conversation listener internally, so clients don't have to make a
separate `AddConversationListener` call like they do today.

For consistency, also updated `model/list` and `feedback/upload` (naming
conventions, list API params).
2025-11-05 20:28:43 +00:00
Gabriel Peal
79aa83ee39 Update rmcp to 0.8.5 (#6261)
Picks up https://github.com/modelcontextprotocol/rust-sdk/pull/511 which
should fix todoist and some other MCP server oauth and may further
resolve issues in https://github.com/openai/codex/issues/5045
2025-11-05 14:20:30 -05:00
Eric Traut
c4ebe4b078 Improved token refresh handling to address "Re-connecting" behavior (#6231)
Currently, when the access token expires, we attempt to use the refresh
token to acquire a new access token. This works most of the time.
However, there are situations where the refresh token is expired,
exhausted (already used to perform a refresh), or revoked. In those
cases, the current logic treats the error as transient and attempts to
retry it repeatedly.

This PR changes the token refresh logic to differentiate between
permanent and transient errors. It also changes callers to treat the
permanent errors as fatal rather than retrying them. And it provides
better error messages to users so they understand how to address the
problem. These error messages should also help us further understand why
we're seeing examples of refresh token exhaustion.

Here is the error message in the CLI. The same text appears within the
extension.

<img width="863" height="38" alt="image"
src="https://github.com/user-attachments/assets/7ffc0d08-ebf0-4900-b9a9-265064202f4f"
/>

I also correct the spelling of "Re-connecting", which shouldn't have a
hyphen in it.

Testing: I manually tested these code paths by adding temporary code to
programmatically cause my refresh token to be exhausted (by calling the
token refresh endpoint in a tight loop more than 50 times). I then
simulated an access token expiration, which caused the token refresh
logic to be invoked. I confirmed that the updated logic properly handled
the error condition.

Note: We earlier discussed the idea of forcefully logging out the user
at the point where token refresh failed. I made several attempts to do
this, and all of them resulted in a bad UX. It's important to surface
this error to users in a way that explains the problem and tells them
that they need to log in again. We also previously discussed deleting
the auth.json file when this condition is detected. That also creates
problems because it effectively changes the auth status from logged in
to logged out, and this causes odd failures and inconsistent UX. I think
it's therefore better not to delete auth.json in this case. If the user
closes the CLI or VSCE and starts it again, we properly detect that the
access token is expired and the refresh token is "dead", and we force
the user to go through the login flow at that time.

This should address aspects of #6191, #5679, and #5505
2025-11-05 10:51:57 -08:00
Ahmed Ibrahim
1a89f70015 refactor Conversation history file into its own directory (#6229)
This is just a refactor of `conversation_history` file by breaking it up
into multiple smaller ones with helper. This refactor will help us move
more functionality related to context management here. in a clean way.
2025-11-05 10:49:35 -08:00
Jeremy Rose
62474a30e8 tui: refactor ChatWidget and BottomPane to use Renderables (#5565)
- introduce RenderableItem to support both owned and borrowed children
in composite Renderables
- refactor some of our gnarlier manual layouts, BottomPane and
ChatWidget, to use ColumnRenderable
- Renderable and friends now handle cursor_pos()
2025-11-05 09:50:40 -08:00
Gabriel Peal
9b538a8672 Upgrade rmcp to 0.8.4 (#6234)
Picks up https://github.com/modelcontextprotocol/rust-sdk/pull/509 which
fixes https://github.com/openai/codex/issues/6164
2025-11-05 00:23:24 -05:00
Andrew Dirksen
95af417923 allow codex to be run from pid 1 (#4200)
Previously it was not possible for codex to run commands as the init
process (pid 1) in linux. Commands run in containers tend to see their
own pid as 1. See https://github.com/openai/codex/issues/4198

This pr implements the solution mentioned in that issue.

Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-04 17:54:46 -08:00
Soroush Yousefpour
fff576cf98 fix(core): load custom prompts from symlinked Markdown files (#3643)
- Discover prompts via fs::metadata to follow symlinks

- Add Unix-only symlink test in custom_prompts.rs

- Update docs/prompts.md to mention symlinks

Fixes #3637

---------

Signed-off-by: Soroush Yousefpour <h.yusefpour@gmail.com>
Co-authored-by: dedrisian-oai <dedrisian@openai.com>
Co-authored-by: Eric Traut <etraut@openai.com>
2025-11-04 17:44:02 -08:00
Lukas
1575f0504c Fix nix build (#6230)
Previously, the `nix build .#default` command fails due to a missing
output hash in the `./codex-rs/default.nix` for `crossterm-0.28.1`:

```
error: No hash was found while vendoring the git dependency crossterm-0.28.1. You can add
a hash through the `outputHashes` argument of `importCargoLock`:

outputHashes = {
 "crossterm-0.28.1" = "<hash>";
};

If you use `buildRustPackage`, you can add this attribute to the `cargoLock`
attribute set.
```

This PR adds the missing hash:

```diff
cargoLock.outputHashes = {
  "ratatui-0.29.0" = "sha256-HBvT5c8GsiCxMffNjJGLmHnvG77A6cqEL+1ARurBXho=";
+ "crossterm-0.28.1" = "sha256-6qCtfSMuXACKFb9ATID39XyFDIEMFDmbx6SSmNe+728=";
};
```

With this change, `nix build .#default` succeeds:

```
> nix build .#default --max-jobs 1 --cores 2

warning: Git tree '/home/lukas/r/github.com/lukasl-dev/codex' is dirty
[1/0/1 built] building codex-rs-0.1.0 (buildPhase)[1/0/1 built] building codex-rs-0.1.0 (buildP[1/0/1 built] building codex-rs-0.1.0 (buildPhase):    [1/0/1 built] building codex-rs-0.1.0 (b[1/0/1 built] building codex-rs-0.1.0 (buildPhase):    Compi[1/0/1 built] building codex-rs-0.1

> ./result/bin/codex
  You are running Codex in /home/lukas/r/github.com/lukasl-dev/codex

  Since this folder is version controlled, you may wish to allow Codex to work in this folder without asking for approval.
  ...
```
2025-11-04 17:07:37 -08:00
Owen Lin
edf4c3f627 [app-server] feat: export.rs supports a v2 namespace, initial v2 notifications (#6212)
**Typescript and JSON schema exports**
While working on Thread/Turn/Items type definitions, I realize we will
run into name conflicts between v1 and v2 APIs (e.g. `RateLimitWindow`
which won't be reusable since v1 uses `RateLimitWindow` from `protocol/`
which uses snake_case, but we want to expose camelCase everywhere, so
we'll define a V2 version of that struct that serializes as camelCase).

To set us up for a clean and isolated v2 API, generate types into a
`v2/` namespace for both typescript and JSON schema.
- TypeScript: v2 types emit under `out_dir/v2/*.ts`, and root index.ts
now re-exports them via `export * as v2 from "./v2"`;.
- JSON Schemas: v2 definitions bundle under `#/definitions/v2/*` rather
than the root.

The location for the original types (v1 and types pulled from
`protocol/` and other core crates) haven't changed and are still at the
root. This is for backwards compatibility: no breaking changes to
existing usages of v1 APIs and types.

**Notifications**
While working on export.rs, I:
- refactored server/client notifications with macros (like we already do
for methods) so they also get exported (I noticed they weren't being
exported at all).
- removed the hardcoded list of types to export as JSON schema by
leveraging the existing macros instead
- and took a stab at API V2 notifications. These aren't wired up yet,
and I expect to iterate on these this week.
2025-11-05 01:02:39 +00:00
Ahmed Ibrahim
d40a6b7f73 fix: Update the deprecation message to link to the docs (#6211)
The deprecation message is currently a bit confusing. Users may not
understand what is `[features].x`. I updated the docs and the
deprecation message for more guidance.

---------

Co-authored-by: Gabriel Peal <gpeal@users.noreply.github.com>
2025-11-04 21:02:27 +00:00
Ahmed Ibrahim
fe54c216a3 ignore deltas in codex_delegate (#6208)
ignore legacy deltas in codex-delegate to avoid this
[issue](https://github.com/openai/codex/pull/6202).
2025-11-04 19:21:35 +00:00
Ahmed Ibrahim
7e068e1094 fix: ignore reasoning deltas because we send it with turn item (#6202)
should fix this:

<img width="2418" height="242" alt="image"
src="https://github.com/user-attachments/assets/f818d00b-ed3a-479b-94a7-e4bc5db6326e"
/>
2025-11-04 08:27:16 -08:00
Celia Chen
d3187dbc17 [App-server] v2 for account/updated and account/logout (#6175)
V2 for `account/updated` and `account/logout` for app server. correspond
to old `authStatusChange` and `LogoutChatGpt` respectively. Followup PRs
will make other v2 endpoints call `account/updated` instead of
`authStatusChange` too.
2025-11-03 22:01:33 -08:00
Robby He
dc2f26f7b5 Fix is_api_message to correctly exclude reasoning messages (#6156)
## Problem

The `is_api_message` function in `conversation_history.rs` had a
misalignment between its documentation and implementation:

- **Comment stated**: "Anything that is not a system message or
'reasoning' message is considered an API message"
- **Code behavior**: Was returning `true` for `ResponseItem::Reasoning`,
meaning reasoning messages were incorrectly treated as API messages

This inconsistency could lead to reasoning messages being persisted in
conversation history when they should be filtered out.

## Root Cause

Investigation revealed that reasoning messages are explicitly excluded
throughout the codebase:

1. **Chat completions API** (lines 267-272 in `chat_completions.rs`)
omits reasoning from conversation history:
   ```rust
   ResponseItem::Reasoning { .. } | ResponseItem::Other => {
       // Omit these items from the conversation history.
       continue;
   }
   ```

2. **Existing tests** like `drops_reasoning_when_last_role_is_user` and
`ignores_reasoning_before_last_user` validate that reasoning should be
excluded from API payloads

## Solution

Fixed the `is_api_message` function to align with its documentation and
the rest of the codebase:

```rust
// Before: Reasoning was incorrectly returning true
ResponseItem::Reasoning { .. } | ResponseItem::WebSearchCall { .. } => true,

// After: Reasoning correctly returns false  
ResponseItem::WebSearchCall { .. } => true,
ResponseItem::Reasoning { .. } | ResponseItem::Other => false,
```

## Testing

- Enhanced existing test to verify reasoning messages are properly
filtered out
- All 264 core tests pass, including 8 chat completions tests that
validate reasoning behavior
- No regressions introduced

This ensures reasoning messages are consistently excluded from API
message processing across the entire codebase.
2025-11-03 20:55:41 -08:00