mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
5e737372ee09db8a0941ca0946385f64a854de61
5907 Commits
-
feat(tui): add configurable keymap support (#18593)
## Why The TUI currently handles keyboard shortcuts as hard-coded event matches spread across app, composer, pager, list, approval, and navigation code. That makes shortcuts hard to customize, makes displayed hints easy to drift from actual behavior, and makes future keymap work riskier because there is no central action inventory. This PR adds the foundation for configurable, action-based keymaps without adding the interactive remapping UI yet. Onboarding intentionally stays on fixed startup shortcuts because users cannot reasonably configure keymaps before completing onboarding. This is PR1 in the keymap stack: - PR1: #18593: configurable keymap foundation - PR2: #18594: `/keymap` picker and guided remapping UI - PR3: #18595: Vim composer mode and the remap option ## Design Notes The new model resolves named actions into concrete runtime bindings once from config, then passes those bindings to the UI surfaces that handle input or render shortcut hints. The main concepts are: - **Context**: a scope where an action is active, such as `global`, `chat`, `composer`, `editor`, `pager`, `list`, or `approval`. - **Action**: a named operation inside a context, such as `global.open_transcript`, `composer.submit`, or `pager.close`. - **Binding**: one or more single-key shortcuts assigned to an action, written as config strings such as `ctrl-t`, `alt-backspace`, or `page-down`. Multi-step sequences such as `ctrl-x ctrl-s`, `g g`, or leader-key flows are not part of this PR. - **Resolution order**: context-specific config wins first, supported global fallbacks come next, and built-in defaults fill in anything unset. - **Explicit unbinding**: an empty array removes an action binding in that scope and does not fall through to a fallback binding. - **Conflict validation**: a resolved keymap rejects duplicate active bindings inside the same scope so one keypress cannot dispatch two actions. ## What Changed - Added `TuiKeymap` config support under `[tui.keymap]`, including typed contexts/actions, key alias normalization, generated schema coverage, and user-facing config errors. - Added `RuntimeKeymap` resolution in `codex-rs/tui/src/keymap.rs`, including fallback precedence, built-in defaults, explicit unbinding, and per-context conflict validation. - Rewired existing TUI handlers to consume resolved keymap actions instead of directly matching hard-coded keys in each component. - Updated key hint rendering and footer/pager/list surfaces so displayed shortcuts follow the resolved keymap. - Kept onboarding shortcuts fixed in `codex-rs/tui/src/onboarding/keys.rs` instead of exposing them through `[tui.keymap]`. ## Validation The branch includes focused coverage for config parsing, key normalization, runtime fallback resolution, explicit unbinding, duplicate-key conflict validation, default keymap consistency, onboarding startup key behavior, and UI hint snapshots affected by resolved key bindings.
Felipe Coury ·
2026-04-28 12:52:25 -03:00 -
Reset TUI keyboard reporting on exit (#19625)
## Why Codex enables enhanced keyboard reporting while the TUI owns the terminal. In iTerm2, exiting the TUI with Ctrl+C can intermittently leave the parent shell receiving raw CSI-u / `modifyOtherKeys` fragments instead of normal key input. Final terminal cleanup should put the parent shell back into normal keyboard reporting even if the terminal misses the usual stack pop. Fixes #19553. ## What Changed - Move TUI keyboard enhancement setup and detection into `tui/src/tui/keyboard_modes.rs`. - Add an exit-only `restore_after_exit()` path that performs the normal keyboard enhancement pop plus unconditional keyboard enhancement and `modifyOtherKeys` resets. - Keep temporary restore paths, such as external-editor handoff, using the balanced stack pop behavior. ## Confidence Medium. This is a speculative fix: I was not able to reproduce the reported iTerm2 behavior manually, but the symptoms line up with terminal keyboard reporting state surviving Codex exit. The added reset sequences are scoped to final TUI shutdown and should be harmless when the terminal is already clean.
Eric Traut ·
2026-04-28 08:51:44 -07:00 -
friel-openai ·
2026-04-28 08:46:13 -07:00 -
feat: house-keeping memories 2 (#20000)
Just move metrics in a dedicated file
jif-oai ·
2026-04-28 17:26:44 +02:00 -
feat: house-keeping memories 1 (#19998)
Just move metrics in a dedicated file
jif-oai ·
2026-04-28 17:11:49 +02:00 -
feat: skip memory startup when Codex rate limits are low (#19990)
## Why Memory startup runs in the background after an eligible turn, but it can consume Codex backend quota at exactly the wrong time: when the user is already near a rate-limit boundary. This PR adds a guard so the memory pipeline backs off when the Codex rate-limit snapshot says the remaining budget is too low. ## What Changed - Added `memories.min_rate_limit_remaining_percent` with a default of `25`, clamped to `0..=100`, and regenerated `core/config.schema.json`. - Added `codex-rs/memories/write/src/guard.rs`, which fetches Codex backend rate limits before memory startup and skips phase 1 / phase 2 when the Codex limit is reached or either tracked window is above the configured usage ceiling. - Keeps startup best-effort: non-Codex auth or rate-limit fetch/client failures preserve the existing memory startup behavior. - Records a `codex.memory.startup` counter with `status=skipped_rate_limit` when startup is skipped. - Added config parsing/clamping coverage and guard unit tests. ## Verification - Added `codex-rs/memories/write/src/guard_tests.rs` for threshold, primary/secondary window, and reached-limit behavior. - Added config tests for TOML parsing and clamping.
jif-oai ·
2026-04-28 17:07:16 +02:00 -
fix: configure AgentIdentity AuthAPI base URL (#19904)
## Summary AgentIdentity runtime loading currently registers tasks against a single hardcoded AuthAPI base URL. That works for production, but local and staging validation may need registration to target a different authapi-login-provider without baking internal staging service URLs into the OSS binary. This PR adds a small config surface for `agent_identity_authapi_base_url` and threads it through the existing auth-loading path as a direct argument. Explicit config wins. Without config, task registration keeps using the production AuthAPI URL, matching the current default behavior. ## Stack 1. openai/codex#19762 - `refactor: make auth loading async` (merged) 2. openai/codex#19763 - `refactor: load agent identity runtime eagerly` 3. This PR - `fix: configure AgentIdentity AuthAPI base URL` 4. openai/codex#19764 - `feat: verify agent identity JWTs with JWKS` ## Design decisions - Keep the existing auth-loading shape and pass the new value as an argument. This avoids another wrapper loader and keeps the call path readable. - Add config instead of embedding internal staging URLs. Environments that need a non-production AuthAPI can configure it explicitly. - Keep the default AuthAPI registration URL as production. `chatgpt_base_url` remains separate and is used by the follow-up JWKS verification PR for fetching public keys from the ChatGPT backend route. - Resolve the AuthAPI base URL inside AgentIdentity loading, because task registration is the only consumer of this value. ## Testing Tests: targeted Rust checks, AgentIdentity auth tests, config schema regeneration, formatter/fix pass, and whitespace diff check.
efrazer-oai ·
2026-04-28 08:06:45 -07:00 -
feat: trigger memories from user turns with cooldown (#19970)
## Why Memory startup was tied to thread lifecycle events such as create, load, and fork. That can run memory work before a thread receives real user input, and it makes startup cost scale with thread management instead of actual turns. Moving the trigger to `thread/sendInput` keeps memory startup aligned with the first real user turn and lets it use the current thread config at turn time. The idea is to prevent ghost cost due to pre-warm triggered by the app Turn-based startup can also make global phase-2 consolidation easier to request repeatedly, so this adds a success cooldown and tightens the default startup scan window. ## What Changed - Start `codex_memories_write::start_memories_startup_task` after a non-empty `thread/sendInput` turn is submitted, instead of from thread create/load/fork paths: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/app-server/src/codex_message_processor.rs#L6477-L6487 - Expose `CodexThread::config()` so app-server can pass the live config into memory startup at turn time. - Add a six-hour successful-run cooldown for global phase-2 consolidation via `SkippedCooldown`: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/state/src/runtime/memories.rs#L963-L966 - Reduce memory startup defaults to at most 2 rollouts over 10 days: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/config/src/types.rs#L31-L34 ## Verification Updated the memory runtime coverage around phase-2 reclaim behavior, including `phase2_global_lock_respects_success_cooldown`. --------- Co-authored-by: Codex <noreply@openai.com>
jif-oai ·
2026-04-28 16:23:13 +02:00 -
Stabilize memory Phase 2 input ordering (#19967)
## Why Phase 2 still needs to choose the most relevant stage-1 memory outputs by usage and recency, but exposing that ranking as the rendered `raw_memories.md` order creates unnecessary large diff. Usage-count or timestamp changes can reshuffle otherwise unchanged memories, making the workspace diff noisy and giving the consolidation prompt a misleading recency signal from file position. This fix will reduce token consumption ## What Changed - Keep the existing top-N Phase 2 selection ranking by `usage_count`, `last_usage`, `source_updated_at`, and `thread_id`. - Return the selected rows in stable ascending `thread_id` order before syncing Phase 2 filesystem inputs. - Update the memory README, raw memories header, and consolidation prompt so they describe the stable order and tell the prompt to use metadata and workspace diffs instead of file order as the recency signal. - Adjust the memory runtime tests to use deterministic thread IDs and assert the stable return order separately from the ranked selection semantics. ## Test Coverage - Existing memory runtime tests in `codex-rs/state/src/runtime/memories.rs` now cover the stable returned ordering for Phase 2 inputs. --------- Co-authored-by: Codex <noreply@openai.com>
jif-oai ·
2026-04-28 13:32:05 +02:00 -
jif-oai ·
2026-04-28 13:12:51 +02:00 -
feat: fix hinting 2 (#19961)
Fix this: https://github.com/openai/codex/pull/19805#discussion_r3153265562
jif-oai ·
2026-04-28 13:06:41 +02:00 -
feat: split memories part 2 (#19860)
Keep extracting memories out of core and moving the write trigger in the app-server This is temporary and it should move at the client level as a follow-up This makes core fully independant from `codex-memories-write` --------- Co-authored-by: Codex <noreply@openai.com>
jif-oai ·
2026-04-28 13:03:28 +02:00 -
Add MultiAgentV2 root and subagent context hints (#19805)
## Why MultiAgentV2 sessions need startup guidance that matches the role of the thread that is actually being created. Root agents and subagents have different responsibilities, and forked subagents can inherit parent rollout history. If the parent hint is carried into the child context, the child can see stale or conflicting developer guidance before its own session-specific context is added. ## What changed - Added `features.multi_agent_v2.root_agent_usage_hint_text` and `features.multi_agent_v2.subagent_usage_hint_text` config fields, including schema/config parsing support. - Injected the matching root or subagent hint into the initial context as its own developer message when `multi_agent_v2` is enabled. - Filtered configured MultiAgentV2 usage-hint developer messages out of forked parent history so a child thread receives fresh guidance for its own session source/config. - Added targeted coverage for config parsing, initial-context rendering, feature-config deserialization, and forked-history filtering. ## Context examples With this config: ```toml [features.multi_agent_v2] enabled = true root_agent_usage_hint_text = "Root guidance." subagent_usage_hint_text = "Subagent guidance." ``` A root thread initial context renders the root hint as a standalone developer message: ```text [developer] <existing developer context, when present> [developer] Root guidance. ``` A subagent thread initial context renders the subagent hint instead: ```text [developer] <existing developer context, when present> [developer] Subagent guidance. ``` When a subagent forks parent history, any parent developer message whose text exactly matches the configured MultiAgentV2 root or subagent hint is omitted from the forked history before the child receives its fresh subagent hint.
jif-oai ·
2026-04-28 12:31:45 +02:00 -
Add remote plugin uninstall API (#19456)
## Summary - Adds the remote `plugin/uninstall` request form using required `pluginId` plus optional `remoteMarketplaceName`, while preserving local `pluginId` uninstall. - Adds `codex_core_plugins::remote::uninstall_remote_plugin` for the deployed ChatGPT plugin backend uninstall path and validates the backend returns the same id with `enabled: false`. - Routes app-server remote uninstall through feature checks, remote plugin id validation, backend mutation, local downloaded cache deletion, cache clearing, docs, and regenerated protocol schemas. ## Tests - `just write-app-server-schema` - `just fmt` - `cargo test -p codex-app-server-protocol plugin_uninstall_params_serialization_omits_force_remote_sync` - `cargo test -p codex-app-server plugin_uninstall --test all` - `cargo test -p codex-app-server plugin_uninstall` - `cargo build -p codex-cli` - `CODEX_BIN=/Users/xli/code/codex/codex-rs/target/debug/codex python3 /Users/xli/.codex/skills/xli-test-marketplace-api/scripts/run_marketplace_api_matrix.py` (44 pass / 0 fail) - `just fix -p codex-app-server-protocol -p codex-app-server -p codex-tui` - `just fix -p codex-app-server`
xli-oai ·
2026-04-28 03:27:53 -07:00 -
feat: Cache remote plugin bundles on install (#19914)
Remote installs now fetch, validate, download, and cache the plugin bundle locally
xl-openai ·
2026-04-28 00:53:27 -07:00 -
Add
codex updatecommand (#19933)## Why Addresses #9274 Running `codex update` currently starts an interactive Codex session with `update` as the prompt. That is a rough edge for users who expect a direct self-update command after seeing the existing update notice, and it forces them to copy the suggested package-manager command manually. ## What changed - Added a top-level `codex update` subcommand. - Reused the existing install-channel detection and update command runner that the TUI already uses for update prompts. - Exposed the update-action lookup from `codex-tui` so the CLI can invoke the same behavior. - Added CLI coverage to ensure `codex update` is parsed as a subcommand instead of becoming an interactive prompt. ## Verification - `cargo test -p codex-cli` - `cargo test -p codex-tui update_action::tests`
Eric Traut ·
2026-04-27 23:33:59 -07:00 -
app-server-protocol: mark permission profiles experimental (#19899)
## Why `PermissionProfile` is now the canonical internal permissions representation, but the app-server wire shape is still intentionally unstable while the migration continues. Stable app-server clients should not see or generate code for these fields until the wire format settles. ## What changed - Marks every app-server v2 field that sends `PermissionProfile` as experimental, including `command/exec`, `thread/start`, `thread/resume`, `thread/fork`, and `turn/start` request/response payloads. - Enables per-field experimental inspection for `command/exec`, so `permissionProfile` is gated without making the entire method experimental. - Fixes the generated TypeScript schema filter to be comment-aware. The previous scanner treated apostrophes inside doc comments as string delimiters, so some experimental fields leaked into stable TypeScript even though stable JSON was filtered correctly. ## Verification - `cargo test -p codex-app-server-protocol` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19899). * #19900 * __->__ #19899
Michael Bolin ·
2026-04-28 06:08:34 +00:00 -
permissions: store thread sessions as profiles (#19776)
## Why After thread sessions have a required `PermissionProfile`, the TUI no longer needs to cache a separate legacy `SandboxPolicy` in `ThreadSessionState`. Keeping the legacy field would reintroduce two permission authorities in the session cache and make later replay/switching logic easier to get wrong. This PR keeps legacy app-server compatibility at the ingestion boundary: old `sandbox` response values are still accepted, but they are immediately converted to a cwd-anchored profile. ## What Changed - Removes `ThreadSessionState.sandbox_policy`. - Updates active-session permission syncing to write only the current `PermissionProfile`. - Updates thread-read/replay/test fixtures to use profiles as the cached session permission source. - Leaves legacy `sandbox` fields in app-server request/response protocol paths unchanged; those are compatibility boundaries and are converted before entering cached TUI state. ## Verification - `cargo test -p codex-tui thread_session_state::tests --lib` - `cargo test -p codex-tui inactive_thread_started_notification_initializes_replay_session --lib` - `cargo test -p codex-tui thread_events --lib` - `just fix -p codex-tui` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19776). * #19900 * #19899 * __->__ #19776
Michael Bolin ·
2026-04-28 05:49:58 +00:00 -
Allow large remote app-server resume responses (#19920)
## Why Remote TUI resume uses the app-server websocket client. That client inherited tungstenite's default `16 MiB` frame limit, so a large saved session could make `thread/resume` return a single JSON-RPC response frame that the client rejected before the TUI could deserialize or render it. Fixes #19837 ## What Changed - Configure the remote app-server websocket client with a bounded `128 MiB` max frame/message size. - Preserve the concrete remote worker exit reason when completing pending requests after a transport/read failure instead of replacing it with a generic channel-closed error. - Add a regression test that sends a single `>16 MiB` JSON-RPC response frame and verifies the typed request succeeds. Note: This isn't a perfect fix. It really just moves the limit to a much larger value. I looked at a bunch of other potential fixes (both server-side and client-side), and they all involved significant complexity, had backward-compatibility impact, or impacted performance of common use cases. This simple fix should address the vast majority of remote use cases. ## Verification I reproed the problem locally using a long rollout. Verified that fix addresses connection drop.
Eric Traut ·
2026-04-27 22:44:10 -07:00 -
permissions: derive snapshot sandbox projections (#19775)
## Why `ThreadConfigSnapshot` is used by app-server and thread metadata code as a stable view of active runtime settings. Keeping both `sandbox_policy` and `permission_profile` in the snapshot duplicates permission state and makes it possible for the legacy projection to drift from the canonical profile. The legacy `sandbox` value is still needed at app-server compatibility boundaries, so this PR derives it on demand from the snapshot profile and cwd instead of storing it. ## What Changed - Removes `ThreadConfigSnapshot.sandbox_policy`. - Adds `ThreadConfigSnapshot::sandbox_policy()` as a compatibility projection from `permission_profile` plus `cwd`. - Updates app-server response/metadata code and tests to call the projection only where legacy fields still exist. - Keeps snapshot construction profile-only so split filesystem rules, disabled enforcement, and external enforcement remain represented by the canonical profile. ## Verification - `cargo test -p codex-app-server thread_response_permission_profile_preserves_enforcement --lib` - `cargo test -p codex-core dispatch_reclaims_stale_global_lock_and_starts_consolidation --lib` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19775). * #19900 * #19899 * #19776 * __->__ #19775
Michael Bolin ·
2026-04-27 22:30:47 -07:00 -
permissions: make SessionConfigured profile-only (#19774)
## Why `SessionConfiguredEvent` is the internal event that tells clients what permissions are active for a session. Emitting both `sandbox_policy` and `permission_profile` leaves two possible authorities and forces every consumer to decide which one to honor. At this point in the migration, the profile is expressive enough to represent managed, disabled, and external sandbox enforcement, so the internal event can be profile-only. The wire compatibility concern is older serialized events or rollout data that only contain `sandbox_policy`; those still need to deserialize. ## What Changed - Removes `sandbox_policy` from `SessionConfiguredEvent` and makes `permission_profile` required. - Adds custom deserialization so old payloads with only `sandbox_policy` are upgraded to a cwd-anchored `PermissionProfile`. - Updates core event emission and TUI session handling to sync permissions from the profile directly. - Updates app-server response construction to derive the legacy `sandbox` response field from the active thread snapshot instead of from `SessionConfiguredEvent`. - Updates yolo-mode display logic to treat both `PermissionProfile::Disabled` and managed unrestricted filesystem plus enabled network as full-access, while still preserving the distinction between no sandbox and external sandboxing. ## Verification - `cargo test -p codex-protocol session_configured_event --lib` - `cargo test -p codex-protocol serialize_event --lib` - `cargo test -p codex-exec session_configured --lib` - `cargo test -p codex-app-server thread_response_permission_profile_preserves_enforcement --lib` - `cargo test -p codex-core session_configured_reports_permission_profile_for_external_sandbox --lib` - `cargo test -p codex-tui session_configured --lib` - `cargo test -p codex-tui yolo_mode_includes_managed_full_access_profiles --lib` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19774). * #19900 * #19899 * #19776 * #19775 * __->__ #19774
Michael Bolin ·
2026-04-27 22:06:47 -07:00 -
Avoid persisting ShutdownComplete after thread shutdown (#19630)
## Why Fixes #19475. `codex exec` can finish successfully and then emit an `ERROR` on stderr: ```text failed to record rollout items: thread <id> not found ``` That happens because shutdown closes the live thread writer before emitting `ShutdownComplete`. The terminal event was still using the normal `send_event_raw` path, so it tried to append rollout items through a recorder that had already been removed. The answer is correct, but wrappers that treat stderr as failure can retry completed exec runs. This looks like a likely recent regression from [#18882](https://github.com/openai/codex/pull/18882), which routed live thread writes through `ThreadStore` and added the shutdown-time live writer close. I have not bisected this, so the PR treats #18882 as the likely source based on the affected shutdown code path rather than a proven first-bad commit. ## What Changed `ShutdownComplete` now bypasses rollout persistence after thread shutdown and is delivered directly to clients. The shutdown path still records the protocol event in the rollout trace before delivery, preserving trace visibility without attempting a post-shutdown thread-store append. The change also adds a regression test with the in-memory thread store to assert that shutdown creates and shuts down the live thread without appending another item after shutdown.
Eric Traut ·
2026-04-27 22:02:08 -07:00 -
Clarify PR template invitation requirement (#19912)
Addresses #19856 ## Summary - Clarifies that external code contributions are invitation only. - Points contributors to `docs/contributing.md` for the full policy instead of using the previous warning phrasing.
Eric Traut ·
2026-04-27 21:45:15 -07:00 -
[codex-analytics] include user agent in default headers (#17689)
## Summary Adds the standard Codex `User-Agent` to shared default headers so the responses-api WS handshake carries the same client OS and version context as HTTP requests. ## Testing - `cargo test -p codex-core build_ws_client_metadata_includes_window_lineage_and_turn_metadata` - `cargo test -p codex-core --test all responses_websocket`
marksteinbrick-oai ·
2026-04-27 21:32:10 -07:00 -
refactor: load agent identity runtime eagerly (#19763)
## Summary AgentIdentity auth previously registered the process task lazily behind a `OnceCell`. That meant the auth object could be constructed before its runtime task binding was known. This PR makes AgentIdentity auth load the runtime task at auth load time and stores the resulting process task id directly on the auth object. The model-provider call path can then read a concrete task id instead of handling a missing lazy value. ## Stack 1. [refactor: make auth loading async](https://github.com/openai/codex/pull/19762) (merged) 2. **This PR:** [refactor: load AgentIdentity runtime eagerly](https://github.com/openai/codex/pull/19763) 3. [fix: configure AgentIdentity AuthAPI base URL](https://github.com/openai/codex/pull/19904) 4. [feat: verify AgentIdentity JWTs with JWKS](https://github.com/openai/codex/pull/19764) ## Important call sites | Area | Change | | --- | --- | | `AgentIdentityAuth::load` | Registers the process task during auth loading and stores `process_task_id`. | | `CodexAuth::from_agent_identity_jwt` | Awaits AgentIdentity auth loading. | | model-provider auth | Reads a concrete `process_task_id` instead of an optional lazy value. | | AgentIdentity auth tests | Mock task registration now covers eager runtime allocation. | ## Design decisions AgentIdentity auth now treats task registration as part of constructing a usable auth object. That matches how callers use the value: once auth is present, the model-provider path expects the task-scoped assertion data to be ready. ## Testing Tests: targeted Rust auth test compilation, formatter, scoped Clippy fix, and Bazel lock check.
efrazer-oai ·
2026-04-27 21:09:26 -07:00 -
Allow /statusline and /title slash commands during active turns (#19917)
- Marks `/title` and `/statusline` as available during active tasks. - Extends the existing slash-command availability test coverage to include these commands alongside `/goal`.
canvrno-oai ·
2026-04-27 20:57:20 -07:00 -
permissions: require profiles in TUI thread state (#19773)
## Why `ThreadSessionState` is the TUI's cached view of an app-server session. To make `PermissionProfile` the canonical runtime permissions model, cached thread sessions need to always have a profile instead of treating the profile as an optional supplement to a legacy `sandbox` response field. The main compatibility concern is older app-server v2 lifecycle responses that only include `sandbox` and omit `permissionProfile`: - `thread/start` -> `ThreadStartResponse.sandbox` - `thread/resume` -> `ThreadResumeResponse.sandbox` - `thread/fork` -> `ThreadForkResponse.sandbox` Those responses must still hydrate correctly when the TUI is pointed at an older app-server. This PR converts the legacy `sandbox` value into a `PermissionProfile` immediately at response ingestion time, using the response `cwd`, so cached sessions do not carry an optional profile that can later reinterpret cwd-bound grants against a different thread cwd. This fallback is intentionally boundary compatibility. The follow-up PRs in this stack continue the cleanup by making `SessionConfiguredEvent` profile-only, deriving sandbox projections from snapshots only when an API still needs them, and then removing `sandbox_policy` from `ThreadSessionState`. ## What Changed - Makes `ThreadSessionState.permission_profile` required. - Converts legacy app-server response `sandbox` values into a `PermissionProfile` at ingestion time using the response cwd. - Ensures `thread/read` hydration does not reuse a primary session profile that may be anchored to a different cwd; it uses the active widget permission settings for the read thread fallback instead of reusing cached primary-session permissions. - Keeps the app-server request path unchanged: embedded sessions send profiles, while remote sessions continue using legacy sandbox overrides for compatibility. ## Verification - `cargo test -p codex-tui thread_read --lib` - `cargo test -p codex-tui permission_settings_sync_preserves_active_profile_only_rules --lib` - `cargo test -p codex-tui resume_response_restores_turns_from_thread_items --lib` - `cargo test -p codex-tui thread_session_state::tests --lib` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19773). * #19900 * #19899 * #19776 * #19775 * #19774 * __->__ #19773
Michael Bolin ·
2026-04-27 20:39:06 -07:00 -
Remove ghost snapshots (#19481)
## Summary - Remove `ghost_snapshot` / `GhostCommit` from the Responses API surface and generated SDK/schema artifacts. - Keep legacy config loading compatible, but make undo a no-op that reports the feature is unavailable. - Clean up core history, compaction, telemetry, rollout, and tests to stop carrying ghost snapshot items. ## Testing - Unit tests passed for `codex-protocol`, `codex-core` targeted undo and compaction flows, `codex-rollout`, and `codex-app-server-protocol`. - Regenerated config and app-server schemas plus Python SDK artifacts and verified they match the checked-in outputs.
pakrym-oai ·
2026-04-27 18:48:57 -07:00 -
Stabilize plugin MCP fixture tests (#19452)
## Why Recent `main` CI had repeated flakes in the plugin fixture tests: - `codex-core::all suite::plugins::explicit_plugin_mentions_inject_plugin_guidance` failed in runs [24909500958](https://github.com/openai/codex/actions/runs/24909500958), [24908076251](https://github.com/openai/codex/actions/runs/24908076251), [24906197645](https://github.com/openai/codex/actions/runs/24906197645), and [24898949647](https://github.com/openai/codex/actions/runs/24898949647). - `codex-core::all suite::plugins::plugin_mcp_tools_are_listed` failed in runs [24909500958](https://github.com/openai/codex/actions/runs/24909500958), [24908076251](https://github.com/openai/codex/actions/runs/24908076251), and [24898949647](https://github.com/openai/codex/actions/runs/24898949647). The failures were in the same plugin/MCP fixture family: assertions expected sample plugin guidance or tool inventory, but the test could observe the session before the sample MCP server had finished startup. ## Root Cause `explicit_plugin_mentions_inject_plugin_guidance` submitted the user turn immediately after constructing the session. MCP startup is asynchronous, so on a slower or busier CI runner the prompt could be built before the sample plugin MCP server had reported its tools. That made the test depend on scheduler timing rather than the fixture being ready. `plugin_mcp_tools_are_listed` already needed the same readiness condition, but its wait logic was local to that test. ## What Changed - Added a shared `wait_for_sample_mcp_ready` helper for the plugin fixture tests. - Wait for `McpStartupComplete` before submitting the explicit plugin mention turn. - Reuse the same readiness helper in the MCP tool-listing test. ## Why This Should Be Reliable The tests now wait for the explicit readiness signal from the sample MCP server before asserting guidance or tools derived from that server. This removes the startup race while still exercising the real fixture path, so the assertions should only run after the plugin inventory is deterministic. ## Verification - `cargo test -p codex-core --test all plugins::` - GitHub CI for this PR is passing.
Dylan Hurd ·
2026-04-28 01:14:44 +00:00 -
Refactor exec-server filesystem API into codex-file-system (#19892)
## Summary - Extracted the shared filesystem types and `ExecutorFileSystem` trait into a new `codex-file-system` crate - Switched `codex-config` and `codex-git-utils` to depend on that crate instead of `codex-exec-server` - Kept `codex-exec-server` re-exporting the same API for existing callers ## Testing - Ran `cargo test -p codex-file-system` - Ran `cargo test -p codex-git-utils` - Ran `cargo test -p codex-config` - Ran `cargo test -p codex-exec-server` - Ran `just fix -p codex-file-system`, `just fix -p codex-git-utils`, `just fix -p codex-config`, `just fix -p codex-exec-server` - Ran `just fmt` - Updated and verified the Bazel module lockfile
Michael Zeng ·
2026-04-27 17:43:15 -07:00 -
disallow fileparams metadata for custom mcps (#19836)
## Summary Disallow fileParams metadata for custom MCPs Restricts Codex openai/fileParams handling to the first-party codex_apps MCP server. Custom MCP servers may still advertise the metadata, but Codex now ignores it for upload rewriting, preventing non-Apps tools from receiving signed OpenAI file refs for local paths. Added a regression test for the allowed and denied cases.
colby-oai ·
2026-04-27 20:42:10 -04:00 -
permissions: derive config defaults as profiles (#19772)
## Why This continues the permissions migration by making legacy config default resolution produce the canonical `PermissionProfile` first. The legacy `SandboxPolicy` projection should stay available at compatibility boundaries, but config loading should not create a legacy policy just to immediately convert it back into a profile. Specifically, when `default_permissions` is not specified in `config.toml`, instead of creating a `SandboxPolicy` in `codex-rs/core/src/config/mod.rs` and then trying to derive a `PermissionProfile` from it, we use `derive_permission_profile()` to create a more faithful `PermissionProfile` using the values of `ConfigToml` directly. This also keeps the existing behavior of `sandbox_workspace_write` and extra writable roots after #19841 replaced `:cwd` with `:project_roots`. Legacy workspace-write defaults are represented as symbolic `:project_roots` write access plus symbolic project-root metadata carveouts. Extra absolute writable roots are still added directly and continue to get concrete metadata protections for paths that exist under those roots. The platform sandboxes differ when a symbolic project-root subpath does not exist yet. * **Seatbelt** can encode literal/subpath exclusions directly, so macOS emits project-root metadata subpath policies even if `.git`, `.agents`, or `.codex` do not exist. * **bwrap** has to materialize bind-mount targets. Binding `/dev/null` to a missing `.git` can create a host-visible placeholder that changes Git repo discovery. Binding missing `.agents` would not affect Git discovery, but it would still create a host-visible project metadata placeholder from an automatic compatibility carveout. Linux therefore skips only missing automatic `.git` and `.agents` read-only metadata masks; missing `.codex` remains protected so first-time project config creation goes through the protected-path approval flow. User-authored `read` and `none` subpath rules keep normal bwrap behavior, and `none` can still mask the first missing component to prevent creation under writable roots. ## What Changed - Adds profile-native helpers for legacy workspace-write semantics, including `PermissionProfile::workspace_write_with()`, `FileSystemSandboxPolicy::workspace_write()`, and `FileSystemSandboxPolicy::with_additional_legacy_workspace_writable_roots()`. - Makes `FileSystemSandboxPolicy::workspace_write()` the single legacy workspace-write constructor so both `from_legacy_sandbox_policy()` and `From<&SandboxPolicy>` include the project-root metadata carveouts. - Removes the no-carveout `legacy_workspace_write_base_policy()` path and the `prune_read_entries_under_writable_roots()` cleanup that was only needed by that split construction. - Adds `ConfigToml::derive_permission_profile()` for legacy sandbox-mode fallback resolution; named `default_permissions` profiles continue through the permissions profile pipeline instead of being reconstructed from `sandbox_mode`. - Updates `Config::load()` to start from the derived profile, validate that it still has a legacy compatibility projection, and apply additional writable roots directly to managed workspace-write filesystem policies. - Updates Linux bwrap argument construction so missing automatic `.git`/`.agents` symbolic project-root read-only carveouts are skipped before emitting bind args; missing `.codex`, user-authored `read`/`none` subpath rules, and existing missing writable-root behavior are preserved. - Adds coverage that legacy workspace-write config produces symbolic project-root metadata carveouts, extra legacy workspace writable roots still protect existing metadata paths such as `.git`, and bwrap skips missing `.git`/`.agents` project-root carveouts while preserving missing `.codex` and user-authored missing subpath rules. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19772). * #19776 * #19775 * #19774 * #19773 * __->__ #19772
Michael Bolin ·
2026-04-27 16:50:10 -07:00 -
Streamline review and feedback handlers (#19498)
## Why The remaining review, interrupt, fuzzy search, feedback, and git-diff handlers still had local send-error branches that obscured otherwise simple request handling. This final slice flattens those handlers without changing the public protocol behavior. ## What Changed - Streamlined review start, turn interrupt, fuzzy search session, feedback upload, and git diff handlers in `codex-rs/app-server/src/codex_message_processor.rs`. - Converted validation and upload failures into returned JSON-RPC errors where that avoids nested `send_error`/`return` blocks. - Left unrelated sandbox setup and notification code untouched. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all v2::review -- --test-threads=1`
pakrym-oai ·
2026-04-27 16:36:04 -07:00 -
Add MCP app feature flag (#19884)
## Summary - Add the `enable_mcp_apps` feature flag to the `codex-features` registry - Keep it under development and disabled by default ## Testing - Unit tests for `codex-features` passed - Formatting passed
Matthew Zeng ·
2026-04-27 16:28:49 -07:00 -
Show action required in terminal title (#18372)
Implements #18162 This updates the TUI terminal title to show an explicit action-required state when Codex is blocked on user approval or input. The terminal title now uses the activity title item to cover both active work and blocked-on-user states, while still accepting the legacy spinner config value. Changes - Rename the terminal title item from `spinner` to `activity` while preserving legacy config compatibility - Show `[ ! ] Action Required `while approval or input overlays are active, with a blinking `[ . ]` alternate state - Suppress the normal working spinner while Codex is blocked on user action - Add targeted coverage for action-required title behavior and legacy title-item parsing Testing - Trigger an approval or input modal and confirm the tab title alternates between `[ ! ] Action Required` and `[ . ] Action Required` - Disable the activity title item and confirm the action-required title does not appear - Resolve the prompt and confirm the title returns to the normal spinning/idel state https://github.com/user-attachments/assets/e9ecc530-a6be-4fd7-b9a6-d550a790eb2c
canvrno-oai ·
2026-04-27 15:27:11 -07:00 -
Streamline turn and realtime handlers (#19497)
## Why Turn and realtime handlers had nested validation and send-error branches that made the request path longer than the behavior warranted. This slice keeps the same request semantics while letting the handlers return errors from the failing step. ## What Changed - Streamlined turn start, injected item, and turn steer request handling in `codex-rs/app-server/src/codex_message_processor.rs`. - Applied the same result-returning shape to realtime session response handlers. - Preserved existing request validation and thread-manager interactions. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all v2::turn_start -- --test-threads=1` - `cargo test -p codex-app-server --test all v2::turn_steer -- --test-threads=1` - `cargo test -p codex-app-server --test all v2::thread_inject_items -- --test-threads=1`
pakrym-oai ·
2026-04-27 15:21:59 -07:00 -
Streamline thread resume and fork handlers (#19495)
## Why Thread resume and fork had some of the deepest error-handling indentation in this area because helpers emitted request errors directly. Returning those failures gives the handlers a single request boundary while preserving the async pending-resume behavior. ## What Changed - Converted thread resume helpers in `codex-rs/app-server/src/codex_message_processor.rs` to return `Result` values for validation and view loading failures. - Applied the same pattern to thread fork request handling. - Simplified pending resume error construction by using the shared JSON-RPC error helpers. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all v2::thread_resume -- --test-threads=1` - `cargo test -p codex-app-server --test all v2::thread_fork -- --test-threads=1`
pakrym-oai ·
2026-04-27 15:04:53 -07:00 -
[codex] Trace cancelled inference streams (#19839)
Records cancelled inference streams when Codex stops consuming a provider response before `response.completed`, preserving complete output items observed before cancellation. Also closes still-running inference calls when the owning turn ends, so reduced rollout traces do not leave stale `Running` inference nodes. Covered by focused reducer coverage and a core stream-drop test for partial output preservation.
cassirer-openai ·
2026-04-27 21:58:29 +00:00 -
Streamline thread read handlers (#19494)
## Why The thread read/list handlers mostly assemble views, but their error handling was interleaved with response emission. Returning view-building errors from the helper path keeps those handlers focused on data assembly. ## What Changed - Added a small mapper for `ThreadReadViewError` to JSON-RPC errors in `codex-rs/app-server/src/codex_message_processor.rs`. - Streamlined thread list, loaded-thread, read, turn-list, and summary handlers to produce result values for the request boundary. - Kept the existing invalid-request vs internal-error distinctions for missing or unreadable thread data. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all conversation_summary -- --test-threads=1`
pakrym-oai ·
2026-04-27 14:30:24 -07:00 -
Publish Python SDK with Codex-pinned versioning (#18996)
**note**: a large chunk of this diff comes from regenerating Python types after app-server schema changes on `main`. This is PR 3 of 3 for the Python SDK PyPI publishing split. PR #18862 refreshed the generated SDK surface, and PR #18865 made the runtime package publishable as `openai-codex-cli-bin`; this final PR makes the SDK package publishable as `openai-codex-app-server-sdk` and pins both packages to the same Codex runtime version. The key idea is that the published SDK version is the Codex runtime version. That one version now drives the SDK package version, the exact runtime dependency, the client version reported by the SDK, and the bootstrap runtime pin. This keeps release-time versioning in one lane instead of scattering checked-in literals through the package. ## What changed - Rename the SDK distribution from `codex-app-server-sdk` to `openai-codex-app-server-sdk` for conflict-free PyPI publishing. - Use `stage-sdk --codex-version ...` with one Codex version for both the SDK package version and exact `openai-codex-cli-bin` dependency. - Preserve hidden legacy `--runtime-version` / `--sdk-version` args only to reject mismatched versions during staging. - Map PEP 440 package versions back to Codex release tags for runtime setup downloads, e.g. `0.116.0a1` -> `rust-v0.116.0-alpha.1`. - Derive `codex_app_server.__version__`, the default `AppServerConfig.client_version`, and `_runtime_setup.pinned_runtime_version()` from the SDK package/project version instead of hardcoding duplicate version strings. - Carry the current generated SDK refresh from `main` so `generate-types` stays clean after recent app-server schema changes. - Update `sdk/python/uv.lock` for the renamed editable package. ## Validation - `uv run --extra dev pytest` in `sdk/python` -> 59 passed, 37 skipped. - Targeted `uv run ruff check` for the touched SDK files. - `git diff --check`. - Staged runtime with `--codex-version rust-v0.116.0-alpha.1 --platform-tag macosx_11_0_arm64`. - Staged SDK with `--codex-version rust-v0.116.0-alpha.1`. - Built runtime wheel, SDK wheel, and SDK sdist. - `twine check /tmp/codex-python-pr3-build/dist/*` -> passed. - Clean venv smoke installed `openai-codex-app-server-sdk==0.116.0a1` from local dist and pulled `openai-codex-cli-bin==0.116.0a1`. - Smoke imports passed for `Codex` and `bundled_codex_path()`.
Steve Coffey ·
2026-04-27 14:28:46 -07:00 -
[codex] Shard exec Bazel integration test (#19862)
## Summary - shard `//codex-rs/exec:exec-all-test` into 8 Bazel shards - keep the existing `no-sandbox` test tag unchanged ## Why The Windows Bazel lane has been timing out this aggregated integration test target at the default 300s test timeout. The target runs the combined `codex-rs/exec/tests/all.rs` integration binary; sharding lets Bazel split the Rust test cases across parallel test actions instead of running the whole integration suite as one long action. ## Validation Not run locally, per the Codex repo workflow for development-phase changes. Co-authored-by: Codex <noreply@openai.com>
starr-openai ·
2026-04-27 21:22:53 +00:00 -
Streamline thread mutation handlers (#19493)
## Why Thread mutation handlers had many short error branches whose only job was to emit a JSON-RPC error and stop. This slice keeps those errors visible, but lets each handler build a result and return early from validation helpers instead of nesting the main path. ## What Changed - Streamlined thread archive/unarchive, rename, memory, metadata, rollback, compact, background terminal, shell, and guardian handlers in `codex-rs/app-server/src/codex_message_processor.rs`. - Reused shared JSON-RPC error constructors in `codex-rs/app-server/src/bespoke_event_handling.rs` for rollback-related request failures. - Preserved direct `send_error` calls where they remain the simplest boundary for pending async event responses. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all v2::thread_rollback -- --test-threads=1`
pakrym-oai ·
2026-04-27 14:18:55 -07:00 -
[codex-backend] Prefer state git metadata in filtered thread lists (#19874)
### Summary - `thread/list` filtered filesystem results already overlay state DB metadata, but the existing merge only filled missing git fields. - Prefer non-null SQLite git metadata over stale non-null rollout values so persisted branch/SHA/origin updates are reflected in filtered thread lists. - Update the focused merge test to cover stale filesystem git metadata being replaced by state-backed values. ### Testing now getting expected icons <img width="426" height="913" alt="Screenshot 2026-04-27 at 1 45 45 PM" src="https://github.com/user-attachments/assets/027fb7e7-f54d-4353-8423-cb76f3c8f5ac" />
joeytrasatti-openai ·
2026-04-27 21:02:40 +00:00 -
Streamline thread start handler (#19492)
## Why The thread start handler mixed request validation, thread construction, dynamic-tool validation, and JSON-RPC error emission in one nested flow. Returning request errors from the helper path makes the successful setup path easier to follow. ## What Changed - Reworked `thread/start` handling in `codex-rs/app-server/src/codex_message_processor.rs` so helper methods return `Result` and the handler emits one result. - Moved dynamic-tool validation failures into returned JSON-RPC errors instead of local `send_error` branches. - Preserved the existing thread creation and task-spawning behavior. ## Verification - `cargo check -p codex-app-server` - `cargo test -p codex-app-server --test all v2::dynamic_tools -- --test-threads=1` - `cargo test -p codex-app-server --test all v2::turn_start -- --test-threads=1`
pakrym-oai ·
2026-04-27 13:56:20 -07:00 -
permissions: remove cwd special path (#19841)
## Why The experimental `PermissionProfile` API had both `:cwd` and `:project_roots` special filesystem paths, which made the permission root ambiguous. This PR removes the unstable `current_working_directory` special path before the permissions API is stabilized, so callers use `:project_roots` for symbolic project-root access. ## What changed - Removes `FileSystemSpecialPath::CurrentWorkingDirectory` from protocol and app-server protocol models, plus regenerated app-server JSON/TypeScript schemas. - Replaces internal `:cwd` permission entries with `:project_roots` entries. - Keeps the existing cwd-update behavior for legacy-shaped workspace-write profiles, while removing the deleted `CurrentWorkingDirectory` case from that compatibility path. - Keeps `PermissionProfile::workspace_write()` as the reusable symbolic workspace-write helper, with docs noting that `:project_roots` entries resolve at enforcement time. - Updates app-server docs/examples and approval UI labeling to stop advertising `:cwd` as a permission token. ## Compatibility Persisted rollout items may contain the old `{"kind":"current_working_directory"}` tag from earlier experimental `permissionProfile` snapshots. This PR keeps that tag as a deserialize-only alias for `ProjectRoots { subpath: None }`, while continuing to serialize only the new `project_roots` tag. ## Follow-up This PR intentionally does not introduce an explicit project-root set on `SessionConfiguration` or runtime sandbox resolution. Today, the resolver still uses the active cwd as the single implicit project root. A follow-up should model project roots separately from tool cwd so `:project_roots` entries can resolve against the configured project roots, and resolve to no entries when there are no project roots. ## Verification - `cargo test -p codex-protocol permissions:: --lib` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-sandboxing -p codex-exec-server --lib` - `cargo test -p codex-core session_configuration_apply_ --lib` - `cargo test -p codex-app-server command_exec_permission_profile_project_roots_use_command_cwd --test all` - `cargo test -p codex-tui thread_read_session_state_does_not_reuse_primary_permission_profile --lib` - `cargo test -p codex-tui preset_matching_accepts_workspace_write_with_extra_roots --lib` - `cargo test -p codex-config --lib`Michael Bolin ·
2026-04-27 13:41:27 -07:00 -
Preserve TUI markdown list spacing after code blocks (#19706)
## Why Fixes #19702. The TUI markdown renderer could visually attach the next list marker to a fenced code block inside the previous list item, even when the source markdown included a blank line before the next item. That made block-heavy loose lists harder to read, while the desired behavior is still to keep simple lists compact. ## What changed - Track whether the current rendered list item contains a code block. - Preserve one blank separator before the following list marker only when the previous item contained a code block. - Add regression coverage for both paths: code-block list items keep the separator, and simple loose list items stay compact. ## Verification - `cargo test -p codex-tui markdown_render` I also manually verified that the bug exists before and is fixed after. ## Before <img width="437" height="240" alt="Screenshot 2026-04-26 at 1 19 01 PM" src="https://github.com/user-attachments/assets/3bc9d64d-2dba-40d9-9d6b-a1d0b3c0f728" /> ## After <img width="410" height="269" alt="Screenshot 2026-04-26 at 1 18 54 PM" src="https://github.com/user-attachments/assets/19c15bee-da32-455e-a7cb-e05eb85f4ea0" />
Eric Traut ·
2026-04-27 13:40:46 -07:00 -
Delay approval prompts while typing (#19513)
## Why Fixes #7744. Approval modals can currently appear while the user is typing ahead in the TUI composer, which lets plain letters like `y` or `a` get consumed as approval shortcuts instead of staying in the draft input. ## What changed - Track recent composer typing activity in `bottom_pane/mod.rs`. - Delay new approval overlays for 1 second while the composer is active, keeping delayed requests queued until the user is idle. - Preserve the existing active-overlay behavior so approvals that arrive while an approval modal is already open are still queued into that overlay. - Prune delayed approvals when app-server resolution says the request has already been handled. ## Verification Added unit coverage for immediate approvals, delayed approvals, idle deadline reset, typed shortcut letters staying in the composer, shortcut handling after the delay, and resolved delayed-request pruning. Focused `codex-tui` test groups pass locally. The full `cargo test -p codex-tui` run currently aborts in `app::tests::attach_live_thread_for_selection_rejects_unmaterialized_fallback_threads`; that same test also fails when run alone with the same stack overflow. Manual reviewer check: 1. Start the TUI from the repo root: ```bash RUST_LOG=trace just codex \ -c log_dir=<temp-log-dir> \ --ask-for-approval untrusted \ --sandbox workspace-write ``` 2. Submit this prompt: ```text create a file text.txt on my desktop ``` 3. While the agent is preparing the approval request, immediately type text such as `ya this should stay in the composer`. 4. Confirm the typed-ahead `y`/`a` remains in the composer instead of approving the request. 5. Stop typing for about 1 second; the approval modal should then appear. 6. Once the modal is visible, press `y` and confirm the approval shortcut works normally.
Eric Traut ·
2026-04-27 13:20:55 -07:00 -
Fix filtered thread-list resume regression in TUI (#19591)
## Why `codex resume` regressed after [#18502](https://github.com/openai/codex/pull/18502) changed the default `thread/list` scan-and-repair path for metadata-filtered listings. The TUI resume picker uses `thread/list` with source/provider/cwd filters and `useStateDbOnly: false`, which is the intended correctness-preserving mode: it should still consult the filesystem so healthy, missing, or stale SQLite state can be repaired. The regression was that #18502 made that filtered, filesystem-backed path call `reconcile_rollout` for every filesystem hit, and then call it again for each SQLite hit. When `reconcile_rollout` does not already have extracted rollout items, it falls back to loading the full JSONL rollout. That changed the resume picker’s first page from a cheap rollout-head scan plus SQLite read-repair into full-file reads for large sessions, so a few long threads could dominate TUI startup/resume latency. This change addresses the regression by keeping `useStateDbOnly: false` on the correctness-preserving path while avoiding unnecessary full JSONL reads for rows the filesystem scan has already validated. Source/provider/cwd filters can be decided from rollout-head metadata, so non-search resume listings only need the lightweight read-repair path for filesystem hits. Full reconciliation is still used for DB-only filtered rows because those can be stale false positives, and for search listings because search can depend on title metadata that may require scanning the full rollout. This fixes #19483. ## What changed - For non-search filtered listings, repair filesystem hits with the lightweight `read_repair_rollout_path` path instead of full `reconcile_rollout`. - Track thread IDs proven by the filesystem scan and only fully reconcile SQLite-filtered hits that the filesystem scan did not return, preserving stale-DB false-positive cleanup without full-reading every healthy rollout. - Leave search listings on full reconciliation, since search depends on full title metadata rather than only source/provider/cwd metadata from the rollout head. ## Verification - `cargo test -p codex-rollout list_threads` - `cargo test -p codex-app-server thread_list`
Eric Traut ·
2026-04-27 13:02:39 -07:00 -
Cap original-detail image token estimates (#19865)
Clamp original-detail image patch estimates to the current 10k patch budget so large images cannot inflate local context accounting without bound. Add regression coverage for an over-budget image. Fixes openai/codex#19806.
Curtis 'Fjord' Hawthorne ·
2026-04-27 12:39:24 -07:00 -
rhan-oai ·
2026-04-27 19:29:19 +00:00