Commit Graph
220 Commits
Author SHA1 Message Date
Michael BolinandGitHub 7e5c343ef5 feat: make ConstraintError an enum (#8330)
This will make it easier to test for expected errors in unit tests since
we can compare based on the field values rather than the message (which
might change over time). See https://github.com/openai/codex/pull/8298
for an example.

It also ensures more consistency in the way a `ConstraintError` is
constructed.
2025-12-19 19:03:50 +00:00
xl-openaiandGitHub ba835c3c36 Fix tests (#8299)
Fix broken tests.
2025-12-19 02:07:23 +00:00
jif-oaiandGitHub 6c76d17713 feat: collapse "waiting" of unified_exec (#8257)
Screenshots here but check the snapshot files to see it better
<img width="712" height="408" alt="Screenshot 2025-12-18 at 11 58 02"
src="https://github.com/user-attachments/assets/84a2c410-0767-4870-84d1-ae1c0d4c445e"
/>
<img width="523" height="352" alt="Screenshot 2025-12-18 at 11 17 41"
src="https://github.com/user-attachments/assets/d029c7ea-0feb-4493-9dca-af43a0c70c52"
/>
2025-12-18 17:03:43 -08:00
Michael BolinandGitHub 3d4ced3ff5 chore: migrate from Config::load_from_base_config_with_overrides to ConfigBuilder (#8276)
https://github.com/openai/codex/pull/8235 introduced `ConfigBuilder` and
this PR updates all call non-test call sites to use it instead of
`Config::load_from_base_config_with_overrides()`.

This is important because `load_from_base_config_with_overrides()` uses
an empty `ConfigRequirements`, which is a reasonable default for testing
so the tests are not influenced by the settings on the host. This method
is now guarded by `#[cfg(test)]` so it cannot be used by business logic.

Because `ConfigBuilder::build()` is `async`, many of the test methods
had to be migrated to be `async`, as well. On the bright side, this made
it possible to eliminate a bunch of `block_on_future()` stuff.
2025-12-18 16:12:52 -08:00
Ahmed IbrahimandGitHub f084e5264b caribou (#8265)
Welcome caribou

<img width="1536" height="1024" alt="image"
src="https://github.com/user-attachments/assets/2a67b21f-40cf-4518-aee4-691af331ab50"
/>
2025-12-18 08:58:44 -08:00
Ahmed IbrahimandGitHub 374d591311 chores: clean picker (#8232)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2025-12-18 08:41:34 -08:00
Ahmed IbrahimandGitHub 774bd9e432 feat: model picker (#8209)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2025-12-17 16:12:35 -08:00
jif-oaiandGitHub f74e0cda92 feat: unified exec footer (#8117)
# With `unified_exec`
Known tools are correctly casted
<img width="1150" height="312" alt="Screenshot 2025-12-16 at 19 27 28"
src="https://github.com/user-attachments/assets/24150ee5-e88d-461b-a459-483c24784196"
/>
If a session exit the turn, we render it with the "Ran ..."
<img width="1168" height="355" alt="Screenshot 2025-12-16 at 19 27 58"
src="https://github.com/user-attachments/assets/3f00b60c-2d57-4f9d-a201-9cc8388957cb"
/>
If a session does not exit during the turn, it is closed at the end of
the turn but this is not rendered
<img width="642" height="342" alt="Screenshot 2025-12-16 at 19 34 37"
src="https://github.com/user-attachments/assets/c2bd9283-7017-4915-ba73-c52199b0b28e"
/>

# Without `unified_exec`
No changes
<img width="740" height="603" alt="Screenshot 2025-12-16 at 19 31 21"
src="https://github.com/user-attachments/assets/ca5d90fe-a9b2-42ba-bcd7-3e98c4ed22e8"
/>
2025-12-17 17:12:04 +00:00
jif-oaiandGitHub ac6ba286aa feat: experimental menu (#8071)
This will automatically render any `Stage::Beta` features.

The change only gets applied to the *next session*. This started as a
bug but actually this is a good thing to prevent out of distribution
push

<img width="986" height="288" alt="Screenshot 2025-12-15 at 15 38 35"
src="https://github.com/user-attachments/assets/78b7a71d-0e43-4828-a118-91c5237909c7"
/>


<img width="509" height="109" alt="Screenshot 2025-12-15 at 17 35 44"
src="https://github.com/user-attachments/assets/6933de52-9b66-4abf-b58b-a5f26d5747e2"
/>
2025-12-17 17:08:03 +00:00
gt-oaiandGitHub 9352c6b235 feat: Constrain values for approval_policy (#7778)
Constrain `approval_policy` through new `admin_policy` config.

This PR will:
1. Add a `admin_policy` section to config, with a single field (for now)
`allowed_approval_policies`. This list constrains the set of
user-settable `approval_policy`s.
2. Introduce a new `Constrained<T>` type, which combines a current value
and a validator function. The validator function ensures disallowed
values are not set.
3. Change the type of `approval_policy` on `Config` and
`SessionConfiguration` from `AskForApproval` to
`Constrained<AskForApproval>`. The validator function is set by the
values passed into `allowed_approval_policies`.
4. `GenericDisplayRow`: add a `disabled_reason: Option<String>`. When
set, it disables selection of the value and indicates as such in the
menu. This also makes it unselectable with arrow keys or numbers. This
is used in the `/approvals` menu.

Follow ups are:
1. Do the same thing to `sandbox_policy`.
2. Propagate the allowed set of values through app-server for the
extension (though already this should prevent app-server from setting
this values, it's just that we want to disable UI elements that are
unsettable).

Happy to split this PR up if you prefer, into the logical numbered areas
above. Especially if there are parts we want to gavel on separately
(e.g. admin_policy).

Disabled full access:
<img width="1680" height="380" alt="image"
src="https://github.com/user-attachments/assets/1fb61c8c-1fcb-4dc4-8355-2293edb52ba0"
/>

Disabled `--yolo` on startup:
<img width="749" height="76" alt="image"
src="https://github.com/user-attachments/assets/0a1211a0-6eb1-40d6-a1d7-439c41e94ddb"
/>

CODEX-4087
2025-12-17 16:19:27 +00:00
jif-oaiandGitHub 2041b72da7 chore: dedup review result duplication (#8057) 2025-12-17 09:10:51 +00:00
jif-oaiandGitHub b53889aed5 Revert "feat: unified exec footer" (#8109)
Reverts openai/codex#8067
2025-12-16 17:03:19 +00:00
jif-oaiandGitHub 021c9a60e5 feat: unified exec footer (#8067)
<img width="452" height="205" alt="Screenshot 2025-12-15 at 17 54 44"
src="https://github.com/user-attachments/assets/9ece0b1c-8387-4dfc-b883-c6a68ea1b663"
/>
2025-12-16 16:52:36 +00:00
xl-openaiandGitHub 5d77d4db6b Reimplement skills loading using SkillsManager + skills/list op. (#7914)
refactor the way we load and manage skills:
1. Move skill discovery/caching into SkillsManager and reuse it across
sessions.
2. Add the skills/list API (Op::ListSkills/SkillsListResponse) to fetch
skills for one or more cwds. Also update app-server for VSCE/App;
3. Trigger skills/list during session startup so UIs preload skills and
handle errors immediately.
2025-12-14 09:58:17 -08:00
Michael BolinandGitHub 642b7566df fix: introduce AbsolutePathBuf as part of sandbox config (#7856)
Changes the `writable_roots` field of the `WorkspaceWrite` variant of
the `SandboxPolicy` enum from `Vec<PathBuf>` to `Vec<AbsolutePathBuf>`.
This is helpful because now callers can be sure the value is an absolute
path rather than a relative one. (Though when using an absolute path in
a Seatbelt config policy, we still have to _canonicalize_ it first.)

Because `writable_roots` can be read from a config file, it is important
that we are able to resolve relative paths properly using the parent
folder of the config file as the base path.
2025-12-12 15:25:22 -08:00
c978b6e222 fix: restore MCP startup progress messages in TUI (fixes #7827) (#7828)
## Problem

The introduction of `notify_sandbox_state_change()` in #7112 caused a
regression where the blocking call in `Session::new()` waits for all MCP
servers to fully initialize before returning. This prevents the TUI
event loop from starting, resulting in `McpStartupUpdateEvent` messages
being emitted but never consumed or displayed. As a result, the app
appears to hang during startup, and users do not see the expected
"Booting MCP server: {name}" status line.

Issue: [#7827](https://github.com/openai/codex/issues/7827)

## Solution
This change moves sandbox state notification into each MCP server's
background initialization task. The notification is sent immediately
after the server transitions to the Ready state. This approach:
- Avoids blocking `Session::new()`, allowing the TUI event loop to start
promptly.
- Ensures each MCP server receives its sandbox state before handling any
tool calls.
- Restores the display of "Booting MCP server" status lines during
startup.

## Key Changes
- Added `ManagedClient::notify_sandbox_state()` method.
- Passed sandbox_state to `McpConnectionManager::initialize()`.
- Sends sandbox state notification in the background task after the
server reaches Ready status.
- Removed blocking notify_sandbox_state_change() methods.
- Added a chatwidget snapshot test for the "Booting MCP server" status
line.

## Regression Details

Regression was bisected to #7112, which introduced the blocking
behavior.

---------

Co-authored-by: Michael Bolin <bolinfest@gmail.com>
Co-authored-by: Michael Bolin <mbolin@openai.com>
2025-12-12 22:07:03 +00:00
Victor VannaraandGitHub 95f7d37ec6 Fix misleading 'maximize' high effort description on xhigh models (#7874)
## Notes
- switch misleading High reasoning effort descriptions from "Maximizes
reasoning depth" to "Higher reasoning depth" across models with xhigh
reasoning. Affects GPT-5.1 Codex Max and Robin
- refresh model list fixtures and chatwidget snapshots to match new copy

## Revision
- R2: Change 'Higher' to 'Greater'
- R1: Initial

## Testing

<img width="583" height="142" alt="image"
src="https://github.com/user-attachments/assets/1ddd8971-7841-4cb3-b9ba-91095a7435d2"
/>

<img width="838" height="142" alt="image"
src="https://github.com/user-attachments/assets/79aaedbf-7624-4695-b822-93dea7d6a800"
/>
2025-12-11 16:38:52 -08:00
pakrym-oaiandGitHub bb8fdb20dc Revert "Only show Worked for after the final assistant message" (#7884)
Reverts openai/codex#7854
2025-12-11 09:11:42 -08:00
238ce7dfad feat: robin (#7882)
<img width="554" height="554" alt="image"
src="https://github.com/user-attachments/assets/aa86f4c8-fb34-4b0e-8b03-3a9980dfdb08"
/>

---------

Co-authored-by: Dylan Hurd <dylan.hurd@openai.com>
2025-12-11 09:04:08 -08:00
dca7f4cb60 fix(stuff) (#7855)
Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
2025-12-11 00:39:47 -08:00
pakrym-oaiandGitHub 83aac0f985 Only show Worked for after the final assistant message (#7854)
Before:
<img width="1908" height="246" alt="image"
src="https://github.com/user-attachments/assets/f4d5993a-8d37-4982-a6fd-d37f449215b2"
/>
After:
<img width="1102" height="586" alt="image"
src="https://github.com/user-attachments/assets/e833140d-690a-4c33-8bc7-e2b69b9dc92d"
/>
2025-12-10 21:13:13 -08:00
Ahmed IbrahimandGitHub 321625072a Show the default model in model picker (#7838)
See the snapshot
2025-12-10 14:01:18 -08:00
xl-openaiandGitHub b36ecb6c32 Inject SKILL.md when it's explicitly mentioned. (#7763)
1. Skills load once in core at session start; the cached outcome is
reused across core and surfaced to TUI via SessionConfigured.
2. TUI detects explicit skill selections, and core injects the matching
SKILL.md content into the turn when a selected skill is present.
2025-12-10 13:59:17 -08:00
Ahmed IbrahimandGitHub cb9a189857 make model optional in config (#7769)
- Make Config.model optional and centralize default-selection logic in
ModelsManager, including a default_model helper (with
codex-auto-balanced when available) so sessions now carry an explicit
chosen model separate from the base config.
- Resolve `model` once in `core` and `tui` from config. Then store the
state of it on other structs.
- Move refreshing models to be before resolving the default model
2025-12-10 11:19:00 -08:00
Eric TrautandGitHub c4af707e09 Removed experimental "command risk assessment" feature (#7799)
This experimental feature received lukewarm reception during internal
testing. Removing from the code base.
2025-12-10 09:48:11 -08:00
jif-oaiandGitHub 0ad54982ae chore: rework unified exec events (#7775) 2025-12-10 10:30:38 +00:00
Gav VermaandGitHub 6fa24d65f5 Express rate limit warning as % remaining (#7795)
<img width="342" height="264" alt="image"
src="https://github.com/user-attachments/assets/f1e932ff-c550-47b3-9035-0299ada4998d"
/>

Earlier, the warning was expressed as consumed% whereas status was
expressed as remaining%. This change brings the two into sync to
minimize confusion and improve visual consistency.
2025-12-09 21:17:57 -08:00
Ahmed IbrahimandGitHub 382f047a10 Remove legacy ModelInfo and merge it with ModelFamily (#7748)
This is a step towards removing the need to know `model` when
constructing config. We firstly don't need to know `model_info` and just
respect if the user has already set it. Next step, we don't need to know
`model` unless the user explicitly set it in `config.toml`
2025-12-08 15:29:37 -08:00
Josh McKinneyandGitHub a9f566af7b Restore status header after stream recovery (#7660)
## Summary
- restore the previous status header when a non-error event arrives
after a stream retry
- add a regression test to ensure the reconnect banner clears once
streaming resumes

## Testing
- cargo fmt -- --config imports_granularity=Item
- cargo clippy --fix --all-features --tests --allow-dirty -p codex-tui
- NO_COLOR=0 cargo test -p codex-tui *(fails: vt100 color assertion
tests expect colored cells but the environment returns Default colors
even with NO_COLOR cleared and TERM/COLORTERM set)*

------
[Codex
Task](https://chatgpt.com/codex/tasks/task_i_69337f8c77508329b3ea85134d4a7ac7)
2025-12-08 14:33:00 -08:00
Ahmed IbrahimandGitHub 71c75e648c Enhance model picker (#7709)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2025-12-08 14:22:51 -08:00
Ahmed IbrahimandGitHub 222a491570 load models from disk and set a ttl and etag (#7722)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2025-12-08 13:43:04 -08:00
Ahmed IbrahimandGitHub d08efb1743 Wire with_remote_overrides to construct model families (#7621)
- This PR wires `with_remote_overrides` and make the
`construct_model_families` an async function
- Moves getting model family a level above to keep the function `sync`
- Updates the tests to local, offline, and `sync` helper for model
families
2025-12-05 10:40:15 -08:00
zhao-oaiandGitHub b8eab7ce90 fix: taking plan type from usage endpoint instead of thru auth token (#7610)
pull plan type from the usage endpoint, persist it in session state /
tui state, and propagate through rate limit snapshots
2025-12-04 23:34:13 -08:00
Ahmed IbrahimandGitHub 7b359c9c8e Call models endpoint in models manager (#7616)
- Introduce `with_remote_overrides` and update
`refresh_available_models`
- Put `auth_manager` instead of `auth_mode` on `models_manager`
- Remove `ShellType` and `ReasoningLevel` to use already existing
structs
2025-12-04 18:28:03 -08:00
zhao-oaiandGitHub 87666695ba execpolicy tui flow (#7543)
## Updating the `execpolicy` TUI flow

In the TUI, when going through the command approval flow, codex will now
ask the user if they would like to whitelist the FIRST unmatched command
among a chain of commands.

For example, let's say the agent wants to run `apple | pear` with an
empty `execpolicy`

Neither apple nor pear will match to an `execpolicy` rule. Thus, when
prompting the user, codex tui will ask the user if they would like to
whitelist `apple`.

If the agent wants to run `apple | pear` again, they would be prompted
again because pear is still unknown. when prompted, the user will now be
asked if they'd like to whitelist `pear`.

Here's a demo video of this flow:


https://github.com/user-attachments/assets/fd160717-f6cb-46b0-9f4a-f0a974d4e710

This PR also removed the `allow for this session` option from the TUI.
2025-12-04 07:58:13 +00:00
zhao-oaiandGitHub 3d35cb4619 Refactor execpolicy fallback evaluation (#7544)
## Refactor of the `execpolicy` crate

To illustrate why we need this refactor, consider an agent attempting to
run `apple | rm -rf ./`. Suppose `apple` is allowed by `execpolicy`.
Before this PR, `execpolicy` would consider `apple` and `pear` and only
render one rule match: `Allow`. We would skip any heuristics checks on
`rm -rf ./` and immediately approve `apple | rm -rf ./` to run.

To fix this, we now thread a `fallback` evaluation function into
`execpolicy` that runs when no `execpolicy` rules match a given command.
In our example, we would run `fallback` on `rm -rf ./` and prevent
`apple | rm -rf ./` from being run without approval.
2025-12-03 23:39:48 -08:00
zhao-oaiandGitHub e925a380dc whitelist command prefix integration in core and tui (#7033)
this PR enables TUI to approve commands and add their prefixes to an
allowlist:
<img width="708" height="605" alt="Screenshot 2025-11-21 at 4 18 07 PM"
src="https://github.com/user-attachments/assets/56a19893-4553-4770-a881-becf79eeda32"
/>

note: we only show the option to whitelist the command when 
1) command is not multi-part (e.g `git add -A && git commit -m 'hello
world'`)
2) command is not already matched by an existing rule
2025-12-03 23:17:02 -08:00
Ahmed IbrahimandGitHub 67e67e054f Migrate codex max (#7566)
- make codex max the default
- fix: we were doing some async work in sync function which caused tui
to panic
2025-12-03 20:54:48 -08:00
Ahmed IbrahimandGitHub 8da91d1c89 Migrate tui to use models manager (#7555)
- This PR treats the `ModelsManager` like `AuthManager` and propagate it
into the tui, replacing the `builtin_model_presets`
- We are also decreasing the visibility of `builtin_model_presets`

based on https://github.com/openai/codex/pull/7552
2025-12-03 18:00:47 -08:00
xl-openaiandGitHub 9a50a04400 feat: Support listing and selecting skills via $ or /skills (#7506)
List/Select skills with $-mention or /skills
2025-12-03 15:12:46 -08:00
Ahmed IbrahimandGitHub 71504325d3 Migrate model preset (#7542)
- Introduce `openai_models` in `/core`
- Move `PRESETS` under it
- Move `ModelPreset`, `ModelUpgrade`, `ReasoningEffortPreset`,
`ReasoningEffortPreset`, and `ReasoningEffortPreset` to `protocol`
- Introduce `Op::ListModels` and `EventMsg::AvailableModels`

Next steps:
- migrate `app-server` and `tui` to use the introduced Operation
2025-12-03 20:30:43 +00:00
Ahmed IbrahimandGitHub 2ad980abf4 add slash resume (#7302)
`codex resume` isn't that discoverable. Adding it to the slash commands
can help
2025-12-03 11:25:44 -08:00
jif-oaiandGitHub 45f3250eec feat: codex tool tips (#7440)
<img width="551" height="316" alt="Screenshot 2025-12-01 at 12 22 26"
src="https://github.com/user-attachments/assets/6ca3deff-8ef8-4f74-a8e1-e5ea13fd6740"
/>
2025-12-03 16:29:13 +00:00
zhao-oaiandGitHub 5ebdc9af1b persisting credits if new snapshot does not contain credit info (#7490)
in response to incoming changes to responses headers where the header
may sometimes not contain credits info (no longer forcing a credit
check)
2025-12-02 16:23:24 -05:00
Ahmed IbrahimandGitHub 127e307f89 Show token used when context window is unknown (#7497)
- Show context window usage in tokens instead of percentage when the
window length is unknown.
2025-12-02 11:45:50 -08:00
jif-oaiandGitHub 4b78e2ab09 chore: review everywhere (#7444) 2025-12-02 11:26:27 +00:00
jif-oaiandGitHub aaec8abf58 feat: detached review (#7292) 2025-11-28 11:34:57 +00:00
jif-oaiandGitHub 28ff364c3a feat: update process ID for event handling (#7261) 2025-11-25 14:21:05 -08:00
iceweasel-oaiandGitHub 981e2f742d correctly recognize WorkspaceWrite policy on /approvals (#7301)
the `/approvals` popup fails to recognize that the CLI is in
WorkspaceWrite mode if that policy has extra bits, like `writable_roots`
etc.

This change matches the policy, ignoring additional config aspects.
2025-11-25 12:41:00 -08:00
jif-oaiandGitHub b897880378 chore: dedup unified exec "waited" rendering (#7256)
From
<img width="477" height="283" alt="Screenshot 2025-11-24 at 18 02 25"
src="https://github.com/user-attachments/assets/724d1d68-c994-417e-9859-ada8eb173b4c"
/>
To
<img width="444" height="174" alt="Screenshot 2025-11-24 at 18 02 40"
src="https://github.com/user-attachments/assets/40f91247-6d55-4428-84d1-f39c912ac2e7"
/>
2025-11-24 20:45:40 +00:00