mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
af49d38373d637c858b3510d9f0cd3da96c52856
247 Commits
-
Support compact SessionStart hooks (#21272)
# Why Compaction replaces the live conversation history, so hooks that use `SessionStart` to re-inject durable model context need a way to run again after that rewrite. Related - #19905 adds dedicated compact lifecycle hooks # What - add `compact` as a supported `SessionStart` source and matcher value - change pending `SessionStart` state from a single slot to a small FIFO queue so `resume` / `startup` / `clear` can be preserved alongside a later `compact` - drain all queued `SessionStart` sources before the next model request, preserving their original order # Testing The new integration coverage verifies both the basic `compact` matcher path and the stacked `resume` -> `compact` case where both hooks contribute `additionalContext` to the next model turn.
Abhinav ·
2026-05-20 20:46:19 +00:00 -
feat: account active goal progress in the goal extension (#23696)
## Why The goal extension can create and surface goals, but the live turn-accounting path still stopped short of persisting active-goal progress. That leaves token and wall-clock usage, plus `ThreadGoalUpdated` events, out of sync with the extension boundary once work actually advances or a goal transitions out of active state. ## What changed - Teach `GoalAccountingState` to track the current turn, active goal, token deltas, and wall-clock progress snapshots against the persisted goal id. - Flush active-goal accounting from tool-finish, turn-stop, and turn-abort lifecycle hooks, and emit `ThreadGoalUpdated` events when persisted progress changes. - Route `create_goal` and `update_goal` through the same accounting state so new goals start from the right baseline, final progress is flushed before status changes, and `update_goal` can mark a goal `blocked` as well as `complete`. - Keep budget-limited goals accruing through the end of the turn while clearing local active-goal state once a turn or explicit update is finished. - Expand backend and lifecycle coverage around store ids, baseline reset, tool-finish accounting, budget-limited carry-through, and blocked-goal updates. ## Testing - Added focused backend coverage in `codex-rs/ext/goal/tests/goal_extension_backend.rs` for baseline reset, tool-finish accounting, budget-limited turns, and blocked-goal updates. - Extended `codex-rs/core/src/session/tests.rs` to assert that lifecycle inputs expose the expected session, thread, and turn store ids.
jif-oai ·
2026-05-20 18:36:37 +02:00 -
feat: expose turn-start metadata to extensions (#23688)
## Why The goal extension needs more context when a turn starts than `turn_store` alone provides. In particular, goal accounting needs the stable turn id, the effective collaboration mode, and the cumulative token-usage baseline captured at turn start so it can: - suppress goal accounting for plan-mode turns - compute exact per-turn deltas from cumulative `total_token_usage` snapshots instead of relying on the most recent usage event alone - keep the extension-owned accounting path aligned with the host turn lifecycle ## What - extend `codex_extension_api::TurnStartInput` to expose `turn_id`, `collaboration_mode`, and `token_usage_at_turn_start` - pass the full `TurnContext` plus the captured token-usage baseline through the turn-start lifecycle emission path - initialize goal turn accounting from the turn-start baseline and collaboration mode - switch goal token accounting to compute deltas from cumulative `total_token_usage` snapshots - add coverage for the new turn-start lifecycle fields and for goal-accounting baseline behavior ## Testing - added `turn_start_lifecycle_exposes_turn_metadata_and_token_baseline` in `codex-rs/core/src/session/tests.rs` - added `ext/goal/tests/accounting.rs` coverage for baseline-aware goal accounting and plan-mode suppression
jif-oai ·
2026-05-20 15:54:29 +02:00 -
feat: async turn item process (#23692)
Mechanical change
jif-oai ·
2026-05-20 15:30:01 +02:00 -
feat: rename 3 (#23669)
Just a mechanical renaming
jif-oai ·
2026-05-20 12:07:06 +02:00 -
Warn on invalid UTF-8 in AGENTS.md files (#23232)
Fixes #23223. ## Why Malformed AGENTS instructions should not fail silently. The reported issue had invalid UTF-8 in a global `AGENTS.md`; before this change, Codex treated that decode failure like a missing file, so the personal instructions disappeared without a user-visible explanation and the rollout had no `# AGENTS.md instructions` block. Project-level AGENTS files already used lossy decoding, so their instructions still appeared, but invalid bytes were replaced without telling the user. Global and project AGENTS files should behave consistently: keep usable instruction text when possible, and surface a diagnostic when bytes had to be replaced. ## What changed Global `AGENTS.override.md` and `AGENTS.md` loading now reads bytes and decodes with replacement characters on invalid UTF-8, matching project-level AGENTS behavior. Both global and project AGENTS loading now emit a startup warning when invalid UTF-8 is found, and both keep the instruction text with invalid byte sequences replaced. Missing files, non-file candidates, empty files, and the existing `AGENTS.override.md` before `AGENTS.md` precedence keep their current behavior. ## How users see it The warnings flow through the existing startup warning surface. App-server clients receive config-time startup warnings as `configWarning` notifications during initialization, and thread startup emits startup warnings as thread-scoped `warning` notifications. Global AGENTS invalid UTF-8 warnings can appear on both surfaces. Project-level AGENTS invalid UTF-8 warnings are discovered while building thread instructions, so they appear as thread-scoped `warning` notifications. Clients that render warning notifications in the conversation surface show the message as a visible diagnostic instead of silently hiding or altering instructions.
Eric Traut ·
2026-05-19 21:56:46 -07:00 -
Move plugin and skill warmup into session startup (#23535)
## Why Plugin and skill loading is useful as warmup and early validation, but session startup does not need to wait for that work before it can continue building the session. Keeping it on the serial startup path adds avoidable latency to every fresh thread start. We still want invalid skill configurations to show up quickly, and we want the warmup to exercise the same plugin and skill manager caches that the normal turn path uses. ## What changed - moved plugin and skill warmup into the session startup async path instead of eagerly awaiting it on the serial setup path - kept the warmup using the session's resolved filesystem/environment context so skill loading still sees the right roots - preserved early skill-load error logging so broken skill configurations still surface during startup - left the per-turn plugin and skill loading path unchanged, so turns still use the normal cached managers ## Testing - Not run locally; relying on CI for validation.
Ahmed Ibrahim ·
2026-05-19 20:05:52 -07:00 -
Split plugin install discovery into list and request tools (#23372)
## Summary - Add `list_available_plugins_to_install` as the inventory step for plugin and connector install suggestions. - Slim `request_plugin_install` so it only handles the actual elicitation, instead of carrying the full discoverable list in its prompt. - Emit send-time telemetry when an install elicitation is dispatched, including requested tool identity in the event payload. - Emit install-result telemetry through `SessionTelemetry`, including tool type, user response action, and completion status. - Update registration and tests to cover the new two-step flow while keeping the existing `tool_suggest` feature gate unchanged. ## Testing - `just fmt` - `cargo test -p codex-tools` - `cargo test -p codex-core request_plugin_install` - `cargo test -p codex-core list_available_plugins_to_install` - `cargo test -p codex-core install_suggestion_tools_can_be_registered_without_search_tool` - `cargo test -p codex-otel manager_records_plugin_install_suggestion_metric` - `cargo test -p codex-otel manager_records_plugin_install_elicitation_sent_metric` - `just fix -p codex-core` - `just fix -p codex-tools` - `just fix -p codex-otel` - `cargo check -p codex-core`
Matthew Zeng ·
2026-05-19 14:45:37 -07:00 -
Make local environment optional in EnvironmentManager (#23369)
## Summary - make `EnvironmentManager` local environment/runtime paths optional - simplify constructor surface around snapshot materialization - rename local env accessors to `require_local_environment` / `try_local_environment` ## Validation - devbox Bazel build for touched crate surfaces - `//codex-rs/exec-server:exec-server-unit-tests` - `//codex-rs/app-server-client:app-server-client-unit-tests` - filtered touched `//codex-rs/core:core-unit-tests` cases
starr-openai ·
2026-05-19 12:55:34 -07:00 -
Add SubagentStart hook (#22782)
# What `SubagentStart` runs once when Codex creates a thread-spawned subagent, before that child sends its first model request. Thread-spawned subagents use `SubagentStart` instead of the normal root-agent `SessionStart` hook. Configured handlers match on the subagent `agent_type`, using the same value passed to `spawn_agent`. When no agent type is specified, Codex uses the default agent type. Hook input includes the normal session-start fields plus: - `agent_id`: the child thread id. - `agent_type`: the resolved subagent type. `SubagentStart` may return `hookSpecificOutput.additionalContext`. That context is added to the child conversation before the first model request. # Lifecycle Scope Only thread-spawned subagents run `SubagentStart`. Internal/system subagents such as Review, Compact, MemoryConsolidation, and Other do not run normal `SessionStart` hooks and do not run `SubagentStart`. This avoids exposing synthetic matcher labels for internal implementation paths. Also the `SessionStart` hook no longer fires for subagents, this matches behavior with other coding agents' implementation # Stack 1. This PR: add `SubagentStart`. 2. #22873: add `SubagentStop`. 3. #22882: add subagent identity to normal hook inputs.
Abhinav ·
2026-05-19 12:45:08 -07:00 -
Make
denycanonical for filesystem permission entries (#23493)## Why Filesystem permission profiles used `none` for deny-read entries, which is less direct than the action the entry actually represents. This change makes `deny` the canonical filesystem permission spelling while preserving compatibility for older configs that still send `none`. ## What changed - rename `FileSystemAccessMode::None` to `Deny` - serialize and generate schemas with `deny` as the canonical value - retain `none` only as a legacy input alias for temporary config compatibility - update filesystem glob diagnostics and regression coverage to use the canonical spelling - refresh config and app-server schema fixtures to match the new wire shape ## Validation - `cargo test -p codex-protocol` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core config_toml_deserializes_permission_profiles --lib` - `cargo test -p codex-core read_write_glob_patterns_still_reject_non_subpath_globs --lib` Earlier in the session, a broad `cargo test -p codex-core` run reached unrelated pre-existing failures in timing/snapshot/git-info tests under this environment; the targeted surfaces touched by this PR passed cleanly.
viyatb-oai ·
2026-05-19 11:03:47 -07:00 -
[codex] Preserve steer input as user input (#23405)
## Why Steered input was queued as a `ResponseInputItem`, then parsed back into a user message before recording. That path loses information that only exists on `UserInput`, such as UI text elements. This change keeps turn-local pending input typed as either original `UserInput` or existing response items, so steered user input reaches user-message recording without being reconstructed from a response item. ## What changed - Add `TurnInput` for active-turn pending input. - Queue `Session::steer_input` as `TurnInput::UserInput`. - Run pending-input hook inspection only for `TurnInput::UserInput`. - Process drained pending input item by item: accepted items are recorded, blocked items append hook context and are skipped. - Remove the pending-input prepend/requeue path. ## Validation - `just fmt` - `just fix -p codex-core` - `RUST_MIN_STACK=16777216 cargo test -p codex-core --lib session::tests::task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input -- --nocapture` - `RUST_MIN_STACK=16777216 cargo test -p codex-core --lib steer_input` - `RUST_MIN_STACK=16777216 cargo test -p codex-core --lib pending_input` - `RUST_MIN_STACK=16777216 cargo test -p codex-core --test all pending_input` - `RUST_MIN_STACK=16777216 cargo test -p codex-core` (unit tests passed: 1835 passed, 0 failed, 4 ignored; integration `all` target failed due missing helper binaries such as `codex`/`test_stdio_server` plus unrelated MCP/search/code-mode expectations)
pakrym-oai ·
2026-05-19 09:47:43 -07:00 -
[codex] Move hook request plumbing into hook runtime (#23388)
## Why `run_turn` was still hand-building hook payloads and lifecycle events for a couple of hook paths. Most hook call sites already delegate request construction and event emission to `hook_runtime`, which keeps turn orchestration focused on model-flow decisions rather than hook plumbing. This also keeps the legacy `after_agent` message extraction next to the legacy hook dispatch instead of leaving response-item walking in `run_turn`. ## What changed - Added `run_stop_hooks` in `hook_runtime` to build `StopRequest`, emit preview start events, run the hook, and emit completion events. - Added `run_legacy_after_agent_hook` in `hook_runtime` to build and dispatch the legacy `AfterAgent` hook payload, including extracting input messages from response items. - Updated `run_turn` to call the hook runtime helpers and keep only the resulting continuation/block/stop decisions inline. - Removed the repeated pending session-start hook check from the run loop. ## Validation - `cargo test -p codex-core hook_runtime`
pakrym-oai ·
2026-05-19 08:41:26 -07:00 -
[codex] Allow empty turn/start requests (#23409)
## Why `turn/start` already accepts an input array on the wire, including an empty array, but core treated empty input as a no-op before the turn could reach the model. App-server clients need to be able to start a real turn even when there is no new user message, for example to let the model proceed from existing thread context. ## What changed - Removed the `run_turn` early return that skipped empty-input turns when there was no pending input. - Kept empty active-turn steering rejected by moving the `steer_input` empty-input check until after core has determined whether there is an active regular turn. - Empty regular turns now refresh `previous_turn_settings` like other regular turns, so follow-up context injection state advances consistently. - Added an app-server v2 integration test proving `turn/start` with `input: []` emits started/completed notifications, sends one Responses request, and does not synthesize an empty user message. ## Validation - `cargo test -p codex-app-server --test all turn_start_with_empty_input_runs_model_request`
pakrym-oai ·
2026-05-19 08:39:45 -07:00 -
Defer v1 multi-agent tools behind tool search (#23144)
Summary: defer v1 multi-agent tools when tool_search and namespace tools are available; keep concise searchable descriptions and move the v1 usage guidance into developer instructions; add targeted coverage. Testing: not run per request; ran just fmt.
jif-oai ·
2026-05-19 15:04:35 +02:00 -
Add
body_after_prefixauto-compact token limit scope (#22870)## Why `model_auto_compact_token_limit` has only been able to budget the full active context. That makes it hard to set a small "growth since compaction" budget for sessions that preserve a large carried window prefix: the preserved prefix can consume the whole budget and force immediate repeated compaction. This PR adds an opt-in `body_after_prefix` scope so callers can apply `model_auto_compact_token_limit` to sampled output and later growth after the current carried prefix, while still forcing compaction before the full model context window is exhausted. ## What changed - Adds `AutoCompactTokenLimitScope` with the existing `total` behavior as the default and a new `body_after_prefix` mode: [`config_types.rs`](https://github.com/openai/codex/blob/973806b1cb35792555bead994cb3ed94656eb171/codex-rs/protocol/src/config_types.rs#L24-L37). - Threads `model_auto_compact_token_limit_scope` through config loading, `Config`, `core-api`, and app-server v2 schema/TypeScript generation. - Records the first observed input-token count for a `body_after_prefix` compaction window and uses it as the baseline when deciding whether the scoped auto-compaction budget is exhausted: [`turn.rs`](https://github.com/openai/codex/blob/973806b1cb35792555bead994cb3ed94656eb171/codex-rs/core/src/session/turn.rs#L743-L781). - Keeps a hard context-window cap in `body_after_prefix`, so scoped budgeting cannot let the active context overrun the usable window. ## Verification Added compact-suite coverage for the two key behaviors: `body_after_prefix` does not re-compact just because the carried prefix is larger than the scoped budget, and it still compacts when the total active context reaches the configured context window: [`compact.rs`](https://github.com/openai/codex/blob/973806b1cb35792555bead994cb3ed94656eb171/codex-rs/core/tests/suite/compact.rs#L3003-L3128).
jif-oai ·
2026-05-19 10:19:46 +00:00 -
Remove ToolsConfig from tool planning (#22835)
## Why `codex-tools` is meant to hold reusable tool primitives, but `ToolsConfig` had become a second copy of core runtime decisions instead of a small shared contract. It carried provider capabilities, auth/model gates, permission and environment state, web/search/image feature gates, multi-agent settings, and goal availability from core into `codex-tools` ([definition](https://github.com/openai/codex/blob/22dd9ad3929253ed24d7ee4f10f238e95ab25f37/codex-rs/tools/src/tool_config.rs#L97), [stored on each `TurnContext`](https://github.com/openai/codex/blob/22dd9ad3929253ed24d7ee4f10f238e95ab25f37/codex-rs/core/src/session/turn_context.rs#L87)). Every session/context variant then had to build and mutate that snapshot before assembling tools. This PR removes that master object instead of renaming it. Tool planning now reads the live `TurnContext`, where `codex-core` already owns those decisions, while `codex-tools` keeps only reusable primitives and a generic `ToolSetBuilder`/`ToolSet` accumulator. ## What Changed - Removed `ToolsConfig` / `ToolsConfigParams` from `codex-tools`; the crate keeps the shared helpers that still belong there, including request-user-input mode selection, shell backend/type resolution, `UnifiedExecShellMode`, and `ToolEnvironmentMode`. - Replaced config-snapshot planning with `ToolRouter::from_turn_context` and a `spec_plan` pipeline over `CoreToolPlanContext`, deriving provider capabilities, auth gates, model support, feature gates, environment count, goal support, multi-agent options, web search, and image generation from the authoritative turn state. - Added generic `codex_tools::ToolSetBuilder` / `ToolSet`, plus the small core adapter needed to accumulate `CoreToolRuntime` values and hosted model specs. - Added the `tool_family::shell` registration module and moved shell/unified-exec/memory accounting call sites to read the narrow per-turn fields directly. - Narrowed `TurnContext` to the remaining explicit per-turn fields needed by planning: `available_models`, `unified_exec_shell_mode`, and `goal_tools_supported`. - Reworked MCP exposure and tool-search setup so deferred/direct MCP behavior is driven by the current turn rather than a precomputed config snapshot. - Replaced the large expected-spec fixture tests with focused behavior-level coverage for shell tools, environments, goal and agent-job gates, MCP direct/deferred exposure, tool search, request-plugin-install, code mode, multi-agent mode, hosted tools, and extension executor dispatch. ## Verification - `cargo check -p codex-tools` - `cargo check -p codex-core --lib` - `cargo test -p codex-tools` - `cargo test -p codex-core spec_plan --lib` - `cargo test -p codex-core router --lib`
jif-oai ·
2026-05-19 11:24:09 +02:00 -
feat: dedicated goal DB (#23300)
## Why Thread goals are moving toward extension-owned runtime behavior, but their persisted state was still stored in the shared state database. This makes the goal store harder to isolate and keeps future storage splits tied to ad hoc runtime plumbing. This PR gives goals their own SQLite database while keeping the existing `StateRuntime` entry point. The goal is to make this the pattern for adding more dedicated runtime databases later. This also reduce load on existing DB and reduce contention ## Limitation Thread preview from goal is not supported anymore. I'm looking into this [EDIT]: solved ## What changed - Added a dedicated `goals_1.sqlite` database with its own `goals_migrations` directory. - Moved `thread_goals` creation into the goals DB migration set. - Dropped the old `thread_goals` table from the main state DB with a normal state migration. There is intentionally no backfill for existing goal rows. - Changed `GoalStore` to be backed only by the goals DB pool. - Removed the old goal-write side effect that filled empty `threads.preview` values from the goal objective. - Added shared runtime DB path metadata so startup, telemetry, `codex doctor`, and repair handling can include future DBs without bespoke path lists. - Updated Bazel compile data so the new goals migration directory is available to `sqlx::migrate!`. ## Verification - `cargo check --tests -p codex-state -p codex-cli -p codex-core -p codex-app-server` - `just fix -p codex-state` - `just fix -p codex-cli` - `just fix -p codex-app-server`
jif-oai ·
2026-05-19 11:11:41 +02:00 -
Preserve context baselines for full-history agent forks (#23352)
## Why Full-history agent forks should continue from the same prompt prefix as the parent. Dropping the stored `TurnContext` baseline forced the child to rebuild startup context on its first turn, which can duplicate developer instructions and also loses the cache continuity that a full-history fork is supposed to preserve. Truncated forks are different: once we keep only the last N turns, the original prompt prefix is no longer intact, so the child must establish a fresh context baseline. ## What changed - Preserve `RolloutItem::TurnContext` when forking with `SpawnAgentForkMode::FullHistory`, and keep dropping it for truncated forks: https://github.com/openai/codex/blob/4090717d94c1fc7f33c9bd122be133a0c5752052/codex-rs/core/src/agent/control.rs#L98-L126 and https://github.com/openai/codex/blob/4090717d94c1fc7f33c9bd122be133a0c5752052/codex-rs/core/src/agent/control.rs#L399-L401 - Remove the special-case MultiAgentV2 usage-hint filtering path. Full-history fork now preserves the cached developer prefix instead of trying to reconstruct part of it. - Extend the fork coverage to assert both sides of the contract: full-history forks keep the parent reference baseline, while last-N forks rebuild context after truncation: https://github.com/openai/codex/blob/4090717d94c1fc7f33c9bd122be133a0c5752052/codex-rs/core/src/agent/control_tests.rs#L603-L759 and https://github.com/openai/codex/blob/4090717d94c1fc7f33c9bd122be133a0c5752052/codex-rs/core/src/agent/control_tests.rs#L854-L977 ## Verification - `cargo test -p codex-core spawn_agent_can_fork_parent_thread_history_with_sanitized_items -- --nocapture` - `RUST_MIN_STACK=16777216 cargo test -p codex-core spawn_agent_fork_last_n_turns_keeps_only_recent_turns -- --nocapture`
jif-oai ·
2026-05-19 10:34:24 +02:00 -
Remove explicit connector tool undeferral (#23390)
## Summary - remove the explicit-connector carveout that kept mentioned app tools directly exposed instead of deferred - keep the surviving explicit-mention reconstruction only for analytics, preserving `codex_app_mentioned` and `codex_app_used.invoke_type` - trim the now-unused prompt/tool-exposure plumbing and refresh coverage around always-defer behavior ## Verification - `just fmt` - `cargo test -p codex-analytics` - `cargo test -p codex-core` *(one transient timeout in `shell_snapshot::tests::macos_zsh_snapshot_includes_sections`; isolated rerun passed)* - `cargo test -p codex-core --lib shell_snapshot::tests::macos_zsh_snapshot_includes_sections` - `cargo test -p codex-core --test all explicit_app_mentions_respect_always_defer` - `cargo test -p codex-core --lib mcp_tool_exposure::tests::always_defer_feature_defers_apps_too` - `just fix -p codex-analytics` - `just fix -p codex-core`
sayan-oai ·
2026-05-18 21:33:46 -07:00 -
[5 of 7] Replace OverrideTurnContext with ThreadSettings (#22508)
**Stack position:** [5 of 7] ## Summary This PR adds `Op::ThreadSettings`, a queued settings-only update mechanism for changing stored thread settings without starting a new turn. It also removes the legacy `Op::OverrideTurnContext` in the same layer, so reviewers can see the replacement and deletion together. ## Changes - Add `Op::ThreadSettings` for settings-only queued updates. - Emit `ThreadSettingsApplied` with the effective thread settings snapshot after core applies an update. - Route settings-only updates through the same submission queue as user input. - Migrate remaining `OverrideTurnContext` tests and callers to the queued `Op::ThreadSettings` path. - Delete `Op::OverrideTurnContext` from the core protocol and submission loop. This stack addresses #20656 and #22090. ## Stack 1. [1 of 7] [Add thread settings to UserInput](https://github.com/openai/codex/pull/23080) 2. [2 of 7] [Remove UserInputWithTurnContext](https://github.com/openai/codex/pull/23081) 3. [3 of 7] [Remove UserTurn](https://github.com/openai/codex/pull/23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](https://github.com/openai/codex/pull/23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](https://github.com/openai/codex/pull/22508) (this PR) 6. [6 of 7] [Add app-server thread settings API](https://github.com/openai/codex/pull/22509) 7. [7 of 7] [Sync TUI thread settings](https://github.com/openai/codex/pull/22510)
Eric Traut ·
2026-05-18 21:03:51 -07:00 -
[codex] Extract turn skill and plugin injections (#23396)
## Why `run_turn` had accumulated the turn-scoped skill, plugin, app, MCP, connector-selection, and analytics setup inline. That made the orchestration path harder to scan even though the actual turn item injection still needs to stay in `run_turn` so ordering is explicit. ## What changed This extracts that setup into `build_skills_and_plugins`, which returns the combined injection `ResponseItem`s and the explicitly enabled connector IDs. `run_turn` now keeps the required orchestration pieces: context update recording, user input handling, connector selection merge, and the explicit per-item `record_conversation_items` calls for injection items. The refactor keeps the change LOC-neutral in `core/src/session/turn.rs` and preserves the existing response-item based injection path. ## Validation - `cargo test -p codex-core collect_explicit_app_ids_from_skill_items` - `just fix -p codex-core`
pakrym-oai ·
2026-05-18 20:33:27 -07:00 -
[3 of 7] Remove UserTurn (#23075)
**Stack position:** [3 of 7] ## Summary This PR finishes the input-op consolidation by moving the remaining `Op::UserTurn` callers onto `Op::UserInput` and deleting `Op::UserTurn`. This touches a lot of files, but it is a low-risk mechanical migration. ## Stack 1. [1 of 7] [Add thread settings to UserInput](https://github.com/openai/codex/pull/23080) 2. [2 of 7] [Remove UserInputWithTurnContext](https://github.com/openai/codex/pull/23081) 3. [3 of 7] [Remove UserTurn](https://github.com/openai/codex/pull/23075) (this PR) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](https://github.com/openai/codex/pull/23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](https://github.com/openai/codex/pull/22508) 6. [6 of 7] [Add app-server thread settings API](https://github.com/openai/codex/pull/22509) 7. [7 of 7] [Sync TUI thread settings](https://github.com/openai/codex/pull/22510)
Eric Traut ·
2026-05-18 19:56:00 -07:00 -
[2 of 7] Remove UserInputWithTurnContext (#23081)
**Stack position:** [2 of 7] ## Summary This PR removes the overlapping `Op::UserInputWithTurnContext` variant now that `Op::UserInput` can carry thread settings overrides directly. ## Stack 1. [1 of 7] [Add thread settings to UserInput](https://github.com/openai/codex/pull/23080) 2. [2 of 7] [Remove UserInputWithTurnContext](https://github.com/openai/codex/pull/23081) (this PR) 3. [3 of 7] [Remove UserTurn](https://github.com/openai/codex/pull/23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](https://github.com/openai/codex/pull/23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](https://github.com/openai/codex/pull/22508) 6. [6 of 7] [Add app-server thread settings API](https://github.com/openai/codex/pull/22509) 7. [7 of 7] [Sync TUI thread settings](https://github.com/openai/codex/pull/22510)
Eric Traut ·
2026-05-18 19:41:33 -07:00 -
[1 of 7] Add thread settings to UserInput (#23080)
**Stack position:** [1 of 7] ## Summary The first three PRs in this stack are a cleanup pass before the actual thread settings API work. Today, core has several overlapping "user input" ops: `UserInput`, `UserInputWithTurnContext`, and `UserTurn`. They differ mostly in how much next-turn state they carry, which makes the later queued thread settings update harder to reason about and review. This PR starts that cleanup by adding the shared `ThreadSettingsOverrides` payload and allowing `Op::UserInput` to carry it. Existing variants remain in place here, so this layer is mostly a behavior-preserving API shape change plus mechanical constructor updates. ## End State After PR3 By the end of PR3, `Op::UserInput` is the only "user input" core op. It can carry optional thread settings overrides for callers that need to update stored defaults with a turn, while callers without updates use empty settings. `Op::UserInputWithTurnContext` and `Op::UserTurn` are deleted. ## End State After PR5 By the end of PR5, core will have only two ops for this area: - `Op::UserInput` for user-input-bearing submissions. - `Op::ThreadSettings` for settings-only updates. ## Stack 1. [1 of 7] [Add thread settings to UserInput](https://github.com/openai/codex/pull/23080) (this PR) 2. [2 of 7] [Remove UserInputWithTurnContext](https://github.com/openai/codex/pull/23081) 3. [3 of 7] [Remove UserTurn](https://github.com/openai/codex/pull/23075) 4. [4 of 7] [Placeholder for OverrideTurnContext cleanup](https://github.com/openai/codex/pull/23087) 5. [5 of 7] [Replace OverrideTurnContext with ThreadSettings](https://github.com/openai/codex/pull/22508) 6. [6 of 7] [Add app-server thread settings API](https://github.com/openai/codex/pull/22509) 7. [7 of 7] [Sync TUI thread settings](https://github.com/openai/codex/pull/22510)
Eric Traut ·
2026-05-18 18:48:35 -07:00 -
cleanup: Remove skill env var dependency prompting (#22721)
Deletes the skill env var dependency prompt feature and its runtime path. env_var entries in skill dependency metadata are now silently ignored during skill loading.
xl-openai ·
2026-05-19 01:24:19 +00:00 -
[codex] Remove external websocket session resets (#23384)
## Why Compaction now installs replacement history inside the session, but the turn and compaction callers were still reaching into `ModelClientSession` to reset websocket transport state after that install. That made a transport-level reset part of the compaction API even though websocket incremental request selection already checks whether the next request is a strict extension of the previous one and falls back to a full `response.create` when it is not. ## What changed - Removed the compaction-side calls to `reset_websocket_session` from `compact.rs` and `session/turn.rs`. - Simplified pre-sampling and mid-turn compaction helpers so they return `CodexResult<()>` instead of carrying a reset flag. - Made `ModelClientSession::reset_websocket_session` private to `client.rs`, leaving only the websocket timeout recovery path inside the client as a caller. ## Validation - `cargo test -p codex-core --test all responses_websocket_creates_on_non_prefix` - `cargo test -p codex-core --test all steered_user_input_waits_for_model_continuation_after_mid_turn_compact` - `cargo test -p codex-core --test all pre_sampling_compact_runs_on_switch_to_smaller_context_model`
pakrym-oai ·
2026-05-19 01:13:38 +00:00 -
[codex] Move pending input into input queue (#22728)
## Why Pending model input was split across `Session`, `TurnState`, and the agent mailbox. That made it easy for new paths to manage queued user input or mailbox delivery outside the intended ownership boundary. This PR consolidates the model-facing input lifecycle behind the session input queue so turn-local pending input, next-turn queued items, and mailbox delivery coordination are owned in one place. ## What Changed - Added `session/input_queue.rs` to own pending input queues and mailbox delivery coordination. - Removed the standalone `agent/mailbox.rs` channel wrapper and store mailbox items directly in the input queue. - Moved pending-input mutations off `TurnState`; `TurnState` now exposes the queue-owned storage directly for now. - Routed abort cleanup, mailbox delivery phase changes, next-turn queued items, and active-turn pending input through `InputQueue`. - Boxed stack-heavy agent resume/fork startup futures that the refactor pushed over the default test stack. - Updated session, task, goal, stream-event, and multi-agent call sites and tests to use the new queue ownership. ## Verification - `cargo test -p codex-core --lib agent::control::tests` - `cargo test -p codex-core --lib agent::control::tests::resume_closed_child_reopens_open_descendants -- --exact` - `cargo test -p codex-core --lib agent::control::tests::spawn_agent_fork_last_n_turns_keeps_only_recent_turns -- --exact` - `cargo test -p codex-core --lib agent::control::tests::resume_thread_subagent_restores_stored_nickname_and_role -- --exact` - `cargo test -p codex-core` was also run; it completed with 1814 passed, 4 ignored, and one timeout in `agent::control::tests::resume_thread_subagent_restores_stored_nickname_and_role`, which passed when rerun in isolation.
pakrym-oai ·
2026-05-18 15:43:01 -07:00 -
[codex] Trim unused TurnContextItem fields (#22709)
## Why `TurnContextItem` is the durable baseline used to reconstruct context diffs across resume/fork. Most of the old persisted-only fields on it are no longer read, so keeping them in rollout snapshots adds schema surface and state that can drift without affecting reconstruction. `summary` is the exception: older Codex versions require it to deserialize `turn_context` records, so keep writing a default compatibility value until that schema surface can be removed safely. ## What changed - Removed the unused persisted fields from `TurnContextItem`: trace ids, user/developer instructions, output schema, and truncation policy. - Kept `summary` with a compatibility comment and made `TurnContext::to_turn_context_item` write `ReasoningSummary::Auto` instead of live turn state. - Updated rollout/context reconstruction fixtures for the retained summary field. ## Verification - `cargo test -p codex-protocol --lib turn_context_item` - `cargo test -p codex-rollout resume_candidate_matches_cwd_reads_latest_turn_context` - `cargo test -p codex-state turn_context` - `cargo test -p codex-core --lib new_default_turn_captures_current_span_trace_id` - `cargo test -p codex-core --lib record_initial_history_resumed_turn_context_after_compaction_reestablishes_reference_context_item` - `cargo test -p codex-core --test all emits_warning_when_resumed_model_differs` - `git diff --check`
pakrym-oai ·
2026-05-18 21:54:36 +00:00 -
goals: keep pause transitions explicit (#23088)
## Problem This addresses several user-reported cases where active goals were paused even though the user had not explicitly asked for that transition: - the guardian approval-review circuit breaker interrupted a turn and implicitly paused the goal - a shutdown in one app-server instance could pause a goal while a second instance was still actively running the same thread - steering-style interrupts could also pause the goal even though they are meant to redirect work, not stop the goal lifecycle The common problem was that core treated `TurnAbortReason::Interrupted` as an implicit request to transition the persisted goal to `paused`. That made unrelated interrupt paths mutate goal state as a side effect, and in the multi-app-server case it allowed stale process teardown to pause a live goal owned by another running client. After this change, transitioning a goal to `paused` is always an explicit action performed by a client or another intentional goal-state mutation. It is never an implicit transition triggered by generic interrupt handling. Refs #22884. ## What changed - Remove the goal runtime path that paused active goals after interrupted task aborts. - Drop the now-unused abort reason from `GoalRuntimeEvent::TaskAborted`. - Update the focused regression coverage so an interrupted active goal still accounts usage but remains `active`.
Eric Traut ·
2026-05-18 11:58:40 -07:00 -
goal: pause continuation loops on usage limits and blockers (#23094)
Addresses #22833, #22245, #23067 ## Why `/goal` can keep synthesizing turns even when the next turn cannot make meaningful progress. Hard usage exhaustion can replay failing turns, and repeated permission or external-resource blockers can keep burning tokens while waiting for user or system intervention. ## What changed - Add resumable `blocked` and `usageLimited` goal states. As with `paused`, goal continuation stops with these states. - Move to `usageLimited` after usage-limit failures. - Allow the built-in `update_goal` tool to set `blocked` only under explicit repeated-impasse guidance. Updated goal continuation prompt to specify that agent should use `blocked` only when it has made at least three attempts to get past an impasse. Most of the files touched by this PR are because of the small app server protocol update. ## Validation I manually reproduced a number of situations where an agent can run into a true impasse and verified that it properly enters `blocked` state. I then resumed and verified that it once again entered `blocked` state several turns later if the impasse still exists. I also manually reproduced the usage-limit condition by creating a simulated responses API endpoint that returns 429 errors with the appropriate error message. Verified that the goal runtime properly moves the goal into `usageLimited` state and TUI UI updates appropriately. Verified that `/goal resume` resumes (and immediately goes back into `ussageLImited` state if appropriate). ## Follow-up PRs Small changes will be needed to the GUI clients to properly handle the two new states.
Eric Traut ·
2026-05-18 11:28:53 -07:00 -
Fix remote turn diff display roots (#23261)
## Why `TurnDiffTracker` computes a display root so turn diffs can be rendered repo-relative. For remote exec-server turns, the selected turn `cwd` may exist only inside the selected environment, but `run_turn` was discovering the git root through the local host filesystem. When that lookup failed, nested remote-session diffs fell back to the nested `cwd` and showed `/tmp/...`-prefixed paths instead of repo-relative paths. ## What changed - Resolve the diff display root from the primary selected turn environment when one exists, using that environment's filesystem and `cwd`. - Add `codex_git_utils::get_git_repo_root_with_fs(...)` so git-root discovery can run against an `ExecutorFileSystem`, including remote environments. - Reuse that helper from `resolve_root_git_project_for_trust(...)` and add coverage for `.git` gitdir-pointer detection. ## Validation - Devbox Bazel: `//codex-rs/core:core-unit-tests --test_filter=get_git_repo_root_with_fs_detects_gitdir_pointer` - Devbox Docker-backed remote-env repro: `//codex-rs/core:core-all-test --test_filter=apply_patch_turn_diff_paths_stay_repo_relative_when_session_cwd_is_nested`
starr-openai ·
2026-05-18 10:53:49 -07:00 -
chore: make token usage async (#23305)
Make the `TokenUsageContributor` async. This will be required for future extension and it's basically free
jif-oai ·
2026-05-18 15:59:06 +02:00 -
chore: isolate thread goal storage behind GoalStore (#23295)
## Why Thread goal persistence is being prepared for a dedicated storage boundary. Before that split, goal-specific reads, writes, accounting, and cleanup were exposed directly on `StateRuntime`, so core and app-server callsites stayed coupled to the full runtime instead of a goal-specific store. This PR introduces that boundary without changing the goal wire API or current persistence behavior. Callers now go through `StateRuntime::thread_goals()` and the new `GoalStore`, while `GoalStore` still uses the existing state DB pool underneath. ## What changed - Added `GoalStore` in `state/src/runtime/goals.rs` and exposed it from `StateRuntime` via `thread_goals()`. - Moved thread-goal reads, writes, status updates, pause, delete, and usage accounting onto `GoalStore`. - Updated core session goal handling, app-server goal RPCs, resume snapshots, and goal tests to use the store boundary. - Kept thread deletion responsible for cascading goal cleanup by deleting the goal through the store only after a thread row is removed. ## Testing - Existing goal persistence, resume, and accounting tests were updated to exercise the new `GoalStore` access path.
jif-oai ·
2026-05-18 14:47:05 +02:00 -
Make extension lifecycle hooks async (#23291)
## Why Extension lifecycle hooks sit on the host/extension boundary, but the current trait surface only allows synchronous callbacks. That forces extensions that need to seed, rehydrate, observe, or flush extension-owned state during thread and turn transitions to either block inside the callback or move async work into separate host plumbing. This PR makes those lifecycle callbacks awaitable so extension implementations can perform async work directly at the lifecycle point where the host already has the relevant session, thread, or turn stores available. ## What changed - Makes `ThreadLifecycleContributor` and `TurnLifecycleContributor` async in `codex-extension-api`. - Awaits thread start/resume/stop and turn start/stop/abort lifecycle callbacks from `codex-core`. - Updates the guardian and memories extensions to implement the async lifecycle trait surface. - Updates the existing lifecycle tests to use async contributor implementations. - Adds `async-trait` to the crates that now expose or implement these async object-safe lifecycle traits. ## Testing - Existing `codex-core` lifecycle tests were updated to cover async implementations for thread stop and turn abort ordering.
jif-oai ·
2026-05-18 13:53:58 +02:00 -
Make multi-agent v2 tool namespace configurable (#23147)
## Summary - Add `features.multi_agent_v2.tool_namespace` with config/schema validation for Responses-compatible namespace values. - Thread the resolved namespace into `ToolsConfig` for normal turns and review turns. - Wrap MultiAgentV2 tool specs and registry names in the configured namespace when namespace tools are supported, while falling back to the plain tool names when they are not. ## Validation - `just fmt` - `just write-config-schema` - `cargo test -p codex-features multi_agent_v2_feature_config -- --nocapture` - `cargo test -p codex-core test_build_specs_multi_agent_v2 -- --nocapture` - `cargo test -p codex-core multi_agent_v2_config -- --nocapture` - `cargo test -p codex-core multi_agent_v2_rejects_invalid_tool_namespace -- --nocapture` - `cargo test -p codex-tools` - `git diff --check`
jif-oai ·
2026-05-17 15:27:43 +02:00 -
test: construct permission profiles directly (#23030)
## Why `SandboxPolicy` is now a legacy compatibility shape, but several tests still built a `SandboxPolicy` only to immediately convert it into `PermissionProfile` for APIs that already accept canonical runtime permissions. Those detours make it harder to audit where legacy sandbox policy is still required, because boundary-only usages are mixed together with ordinary test setup. ## What Changed - Updated tests in `codex-core`, `codex-exec`, `codex-analytics`, and `codex-config` to construct `PermissionProfile` values directly when the code under test takes a permission profile. - Changed exec-policy, request-permissions, session, and sandbox test helpers to pass `PermissionProfile` through instead of converting from `SandboxPolicy` internally. - Left `SandboxPolicy` in place where tests are explicitly exercising legacy compatibility or request/response boundaries. ## Test Plan - `cargo test -p codex-analytics -p codex-config` - `cargo test -p codex-core --lib safety::tests` - `cargo test -p codex-core --lib exec_policy::tests::` - `cargo test -p codex-core --lib exec::tests` - `cargo test -p codex-core --lib guardian_review_session_config` - `cargo test -p codex-core --lib tools::network_approval::tests` - `cargo test -p codex-core --lib tools::runtimes::shell::unix_escalation::tests` - `cargo test -p codex-core --lib managed_network` - `cargo test -p codex-core --test all request_permissions::` - `cargo test -p codex-exec sandbox` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23030). * #23036 * __->__ #23030
Michael Bolin ·
2026-05-16 12:12:37 -07:00 -
Improve goal completion usage reporting (#22907)
## Why Goal completion follow-up turns currently receive a preformatted English usage sentence such as `time used: 2586 seconds`. That nudges the model to echo an awkward raw seconds count in the final reply, even though the tool result already exposes structured usage fields like `goal.timeUsedSeconds`, `goal.tokensUsed`, and `goal.tokenBudget`. ## What changed - Replace the preformatted completion usage sentence with guidance to read the structured goal fields from the tool result. - Preserve token-budget reporting while allowing the model to phrase elapsed time in a concise, human-friendly way that fits the response language. - Update core coverage for both the generated completion guidance and the session flow that forwards it back to the model. ## Verification Previously, it would have output a final message indicating that it "worked for 303 seconds". Now it shows the following: <img width="286" height="35" alt="image" src="https://github.com/user-attachments/assets/d7011880-9449-46a7-856f-4e50ae00eb45" />
Eric Traut ·
2026-05-16 11:49:40 -07:00 -
core: set permission profiles from snapshots (#22920)
## Why #22891 moved the TUI turn-command path to pass `ActivePermissionProfile` instead of the full `PermissionProfile`, but the remaining config/session bridge still accepted the concrete `PermissionProfile` and active profile id as separate arguments. That shape made it too easy for future callers to update the concrete profile and active profile id out of sync. This PR makes the trusted session snapshot path pass one coherent value into `Permissions`, while keeping `requirements.toml` enforcement owned by the existing constrained permission state. ## What Changed - Added `PermissionProfileSnapshot` as the public snapshot value for trusted session/config synchronization. - Changed `Permissions::set_permission_profile_from_session_snapshot()` and `replace_permission_profile_from_session_snapshot()` to take a `PermissionProfileSnapshot`. - Updated the replacement path to derive its constrained `PermissionProfile` from the snapshot, so callers cannot pass a separate profile that disagrees with the snapshot. - Removed the internal tuple-style `PermissionProfileState::set_active_permission_profile()` mutation path. - Updated core session projection and TUI call sites to construct explicit legacy or active snapshots. - Documented the snapshot constructors so legacy use and id/profile mismatch hazards are called out at the API boundary. - Added a focused config test that verifies snapshot updates still respect existing permission constraints. ## How To Review 1. Start with `codex-rs/core/src/config/resolved_permission_profile.rs`; `PermissionProfileSnapshot` is the public wrapper, while `ResolvedPermissionProfile` stays internal. 2. Check `codex-rs/core/src/config/mod.rs` to confirm both session-snapshot setters validate through `PermissionProfileState` and no longer accept loose profile/id pairs. 3. Skim `codex-rs/core/src/session/session.rs` for the session projection path; it now builds the snapshot before installing it. 4. Skim the TUI changes as call-site migration from loose argument pairs to explicit snapshot construction. ## Verification - `cargo test -p codex-core permission_snapshot_setter_preserves_permission_constraints` - `cargo test -p codex-tui status_permissions_` - `cargo test -p codex-tui session_configured_preserves_profile_workspace_roots` - `just fix -p codex-core -p codex-tui`
Michael Bolin ·
2026-05-16 07:26:18 -07:00 -
Preserve image detail in app-server inputs (#20693)
## Summary - Add optional image detail to user image inputs across core, app-server v2, thread history/event mapping, and the generated app-server schemas/types. - Preserve requested detail when serializing Responses image inputs: omitted detail stays on the existing `high` default, while explicit `original` keeps local images on the original-resolution path. - Support `high`/`original` consistently for tool image outputs, including MCP `codex/imageDetail`, code-mode image helpers, and `view_image`.
Curtis 'Fjord' Hawthorne ·
2026-05-15 15:04:04 -07:00 -
core: construct test permission profiles directly (#22795)
## Why The core migration is trying to make `PermissionProfile` the shape tests and runtime code reason about, leaving `SandboxPolicy` only where legacy behavior is explicitly under test. The local `permission_profile_for_sandbox_policy()` test helpers kept new permission-profile tests mentally tied to the old sandbox model even when the equivalent profile is straightforward. ## What Changed - Removed the `permission_profile_for_sandbox_policy()` helper from the network proxy spec tests and session tests. - Replaced legacy conversions for read-only, workspace-write, and full-access cases with `PermissionProfile::read_only()`, `PermissionProfile::workspace_write()`, and `PermissionProfile::Disabled`. - Constructed the external-sandbox session test's `PermissionProfile::External` directly, while preserving the legacy `SandboxPolicy` only where the test still exercises legacy config update behavior. ## How To Review This PR is intentionally test-only. Review the two touched files and check that each replacement preserves the old legacy mapping: - `SandboxPolicy::new_read_only_policy()` -> `PermissionProfile::read_only()` - `SandboxPolicy::new_workspace_write_policy()` -> `PermissionProfile::workspace_write()` - `SandboxPolicy::DangerFullAccess` -> `PermissionProfile::Disabled` - `SandboxPolicy::ExternalSandbox { network_access: Restricted }` -> `PermissionProfile::External { network: Restricted }` ## Verification - `cargo test -p codex-core requirements_allowed_domains_are_a_baseline_for_user_allowlist` - `cargo test -p codex-core start_managed_network_proxy_applies_execpolicy_network_rules` - `cargo test -p codex-core session_configured_reports_permission_profile_for_external_sandbox` - `cargo test -p codex-core managed_network_proxy_decider_survives_full_access_start` - `just fix -p codex-core` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22795). * #22891 * __->__ #22795Michael Bolin ·
2026-05-15 13:09:25 -07:00 -
Move memory prompt injection to app-server extension (#22841)
## Why Memory prompt injection should be owned by the extension path that app-server composes at runtime, not by an inlined special case inside `codex-core`. This keeps `codex-core` focused on session orchestration while allowing the memories extension to own its app-server prompt behavior. ## What Changed - Registers `codex-memories-extension` in the app-server extension registry. - Moves the memory developer-instruction injection out of `core/src/session/mod.rs` and into the memories extension prompt contributor. - Adds config-change handling so the extension keeps its per-thread memory settings in sync after startup. - Leaves memories read/retrieval tools unregistered for now so this PR only changes prompt injection. - Removes the stale `cargo-shear` ignore now that app-server depends on the extension crate. ## Validation Not run locally; validation is left to CI.
jif-oai ·
2026-05-15 16:19:34 +02:00 -
Remove zombie tools spec module (#22820)
## Summary - move tool_user_shell_type out of the old tools::spec module and call it from tools directly - attach the remaining spec planning model tests under spec_plan - delete core/src/tools/spec.rs ## Tests - just fmt - cargo test -p codex-core tools::spec_plan Note: a broader cargo test -p codex-core run on the earlier PR-head worktree still hit the pre-existing stack overflow in agent::control::tests::spawn_agent_fork_last_n_turns_keeps_only_recent_turns.
jif-oai ·
2026-05-15 13:44:58 +02:00 -
Simplify tool executor and registry plumbing (#22636)
## Why The tool runtime path still had a typed output associated type on `ToolExecutor`, plus a core-only `RegisteredTool` adapter and extension-only executor aliases. That made every new shared tool runtime carry extra adapter plumbing before it could participate in core dispatch, extension tools, hook payloads, telemetry, and model-visible spec generation. This PR moves output erasure to the shared executor boundary so core and extension tools can use the same execution contract directly. ## What Changed - Changed `codex_tools::ToolExecutor` to return `Box<dyn ToolOutput>` instead of an associated `Output` type. - Removed the extension-specific `ExtensionToolExecutor` / `ExtensionToolOutput` aliases and exposed `ToolExecutor<ToolCall>` plus `ToolOutput` through `codex-extension-api`. - Reworked core tool registration around `CoreToolRuntime` and `ToolRegistry::from_tools`, removing the extra `RegisteredTool` / `ToolRegistryBuilder` layer. - Consolidated model-visible spec planning and registry construction in `core/src/tools/spec_plan.rs`, including deferred tool search and code-mode-only filtering. - Added `ToolOutput` helpers for post-tool-use hook ids and inputs so MCP, unified exec, extension, and other boxed outputs preserve the same hook payload behavior. - Updated core handlers, memories tools, and the related registry/spec/router tests to use the simplified contract. ## Test Coverage - Updated coverage for tool spec planning, registry lookup, deferred tool search registration, extension tool routing, post-tool-use hook payloads, dispatch tracing, guardian output extraction, and memories extension tool execution.
jif-oai ·
2026-05-15 11:47:54 +02:00 -
[codex] Use compaction_trigger item for remote compaction v2 (#22809)
## Why Remote compaction v2 was still using `context_compaction` as both the request trigger and the compacted output shape. The Responses API now has the landed contract for this flow: Codex sends a dedicated `{ "type": "compaction_trigger" }` input item, and the backend returns the standard `compaction` output item with encrypted content. This aligns the v2 path with that wire contract while preserving the existing local compacted-history post-processing behavior. ## What changed - Add `ResponseItem::CompactionTrigger` and regenerate the app-server protocol schema fixtures. - Send `compaction_trigger` from `remote_compaction_v2` instead of a payload-less `context_compaction`. - Collect exactly one backend `compaction` output item, then reuse the existing compacted-history rebuilding path. - Treat the trigger item as a transient request marker rather than model output or persisted rollout/memory content. ## Verification - `cargo test -p codex-protocol compaction_trigger` - `cargo test -p codex-core remote_compact_v2` - `cargo test -p codex-core compact_remote_v2` - `cargo test -p codex-core responses_websocket_sends_response_processed_after_remote_compaction_v2` - `just write-app-server-schema` - `cargo test -p codex-app-server-protocol schema_fixtures`jif-oai ·
2026-05-15 11:40:35 +02:00 -
app-server: use permission ids and runtime workspace roots (#22611)
## Why This PR builds on [#22610](https://github.com/openai/codex/pull/22610) and is the app-server side of the migration from mutable per-turn `SandboxPolicy` replacement toward selecting immutable permission profiles by id plus mutable runtime workspace roots. Once permission profiles can carry their own immutable `workspace_roots`, app-server no longer needs to mutate the selected `PermissionProfile` just to represent thread-specific filesystem context. The mutable part now lives on the thread as explicit `runtimeWorkspaceRoots`, while `:workspace_roots` remains symbolic until the sandbox is realized for a turn. ## What Changed - Replaced the v2 permission-selection wrapper surface with plain profile ids for `thread/start`, `thread/resume`, `thread/fork`, and `turn/start`. - Removed the API surface for profile modifications (`PermissionProfileSelectionParams`, `PermissionProfileModificationParams`, `ActivePermissionProfileModification`). - Added experimental `runtimeWorkspaceRoots` fields to the thread lifecycle and turn-start APIs. - Threaded runtime workspace roots through core session/thread snapshots, turn overrides, app-server request handling, and command execution permission resolution. - Kept session permission state symbolic so later runtime root updates and cwd-only implicit-root retargeting rebind `:workspace_roots` correctly. - Updated the embedded clients just enough to send and restore the new thread state. - Refreshed the generated schema/TypeScript artifacts and the app-server README to match the new contract. ## Verification Targeted coverage for this layer lives in: - `codex-rs/app-server-protocol/src/protocol/v2/tests.rs` - `codex-rs/app-server/tests/suite/v2/thread_start.rs` - `codex-rs/app-server/tests/suite/v2/thread_resume.rs` - `codex-rs/app-server/tests/suite/v2/turn_start.rs` - `codex-rs/core/src/session/tests.rs` The key regression checks exercise that: - `runtimeWorkspaceRoots` resolve against the effective cwd on thread start. - Profile-declared workspace roots are excluded from the runtime workspace roots returned by app-server. - A turn-level runtime workspace-root update persists onto the thread and is returned by `thread/resume`. - A named permission profile selected on one turn remains symbolic so a later runtime-root-only turn update changes the actual sandbox writes. - A cwd-only turn update retargets the implicit runtime cwd root while preserving additional runtime roots. - The protocol fixtures and generated client artifacts stay in sync with the string-based permission selection contract. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22611). * #22612 * __->__ #22611
Michael Bolin ·
2026-05-14 23:00:05 -07:00 -
permissions: resolve profile identity with constraints (#22683)
## Why This PR is the invariant-cleanup layer that follows the workspace-roots base merged in [#22610](https://github.com/openai/codex/pull/22610). #22610 adds `[permissions.<id>.workspace_roots]` and keeps runtime workspace roots separate from the raw permission profile, but its in-memory representation is intentionally transitional: `Permissions` still carries the selected profile identity next to a constrained `PermissionProfile`. That makes APIs such as `set_constrained_permission_profile_with_active_profile()` fragile because the id and value only mean the right thing when every caller keeps them in sync. This PR introduces a single resolved profile state so profile identity, `extends`, the profile value, and profile-declared workspace roots travel together. The next PR, [#22611](https://github.com/openai/codex/pull/22611), builds on this by changing the app-server turn API to select permission profiles by id plus runtime workspace roots. ## Stack Context - #22610, now merged: adds profile-declared `workspace_roots`, runtime workspace roots, and `:workspace_roots` materialization. - This PR: replaces the parallel active-profile/profile-value fields with `PermissionProfileState`. - #22611: switches app-server turn updates toward profile ids plus runtime workspace roots. - #22612: updates TUI/exec summaries to show the effective workspace roots. Keeping this separate from #22611 is deliberate: reviewers can validate the internal state invariant before reviewing the app-server protocol migration. ## What Changed - Added `ResolvedPermissionProfile::{Legacy, BuiltIn, Named}` and `PermissionProfileState`. - Typed built-in profile ids with `BuiltInPermissionProfileId`. - Moved selected profile identity and profile-declared workspace roots into the resolved state. - Replaced `Permissions` parallel profile fields with one `permission_profile_state`. - Removed `set_constrained_permission_profile_with_active_profile()` from session sync paths. - Kept trusted session replay/`SessionConfigured` compatibility through explicit session snapshot helpers. - Updated session configuration, MCP initialization, app-server, exec, TUI, and guardian call sites to consume `&PermissionProfile` directly. ## Review Guide Start with `codex-rs/core/src/config/resolved_permission_profile.rs`; it is the new invariant boundary. Then review `codex-rs/core/src/config/mod.rs` to see how config loading records active profile identity and profile workspace roots. The remaining call-site changes are mostly mechanical fallout from `Permissions::permission_profile()` returning `&PermissionProfile` instead of `&Constrained<PermissionProfile>`. ## Verification The existing config/session coverage now constructs and asserts through `PermissionProfileState`. The workspace-root config test also asserts that profile-declared roots are preserved in the resolved state, which is the behavior #22611 relies on when runtime roots become mutable through the app-server API. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22683). * #22612 * #22611 * __->__ #22683
Michael Bolin ·
2026-05-14 18:47:44 -07:00 -
Add
user_input_requested_during_turnto MCP turn metadata (#22237)## Why - Similar change as https://github.com/openai/codex/pull/21219 - Without change: MCP tool calls receive `_meta["x-codex-turn-metadata"]` with various key values. - Issue: MCP servers currently do not know if user input was requested during the turn (Ex: Model decides to prompt the user for approval mid-turn before making a possibly risky tool call). MCP servers may want to know this when tracking latency metrics because these instances are inflated. ## What Changed - With change: MCP turn metadata now includes `user_input_requested_during_turn` when a model-visible `request_user_input` call happened earlier in the turn, propagated in `_meta["x-codex-turn-metadata"]`. - `mark_turn_user_input_requested()` is called when user input is requested through either MCP elicitation (`mcp.rs`) or the `request_user_input` tool (`mod.rs`). - MCP tool call `_meta` is now built immediately before execution (`mcp_tool_call.rs`) so user input requested earlier in the same turn, including within the same tool call via elicitation, is reflected in the metadata. - Normal `/responses` turn metadata headers are unchanged. ## Verification - `codex-rs/core/src/session/mcp_tests.rs` - `codex-rs/core/src/tools/handlers/request_user_input_tests.rs` - `codex-rs/core/src/turn_metadata_tests.rs` - `codex-rs/core/tests/suite/search_tool.rs`
mchen-oai ·
2026-05-15 01:26:50 +00:00 -
permissions: support workspace roots in profiles (#22610)
## Why This is the configuration/model half of the alternative permissions migration we discussed as a comparison point for [#22401](https://github.com/openai/codex/pull/22401) and [#22402](https://github.com/openai/codex/pull/22402). The old `workspace-write` model mixes three concerns that we want to keep separate: - reusable profile rules that should stay immutable once selected - user/runtime workspace roots from `cwd`, `--add-dir`, and legacy workspace-write config - internal Codex writable roots such as memories, which should not be shown as user workspace roots This PR gives permission profiles first-class `workspace_roots` so users can opt multiple repositories into the same `:workspace_roots` rules without using broad absolute-path write grants. It also starts separating the raw selected profile from the effective runtime profile by making `Permissions` expose explicit accessors instead of public mutable fields. A representative `config.toml` looks like this: ```toml default_permissions = "dev" [permissions.dev.workspace_roots] "~/code/openai" = true "~/code/developers-website" = true [permissions.dev.filesystem.":workspace_roots"] "." = "write" ".codex" = "read" ".git" = "read" ".vscode" = "read" ``` If Codex starts in `~/code/codex` with that profile selected, the effective workspace-root set becomes: - `~/code/codex` from the runtime `cwd` - `~/code/openai` from the profile - `~/code/developers-website` from the profile The `:workspace_roots` rules are materialized across each root, so `.git`, `.codex`, and `.vscode` stay scoped the same way everywhere. Runtime additions such as `--add-dir` can still layer on later stack entries without mutating the selected profile. ## Stack Shape This PR intentionally stops before the profile-identity cleanup in [#22683](https://github.com/openai/codex/pull/22683) so the base review stays focused on config loading, workspace-root materialization, and compatibility with legacy `workspace-write`. The representation in this PR is therefore transitional: `Permissions` carries enough state to distinguish the raw constrained profile from the effective runtime profile, and there are still call sites that must keep the active profile identity and constrained profile value in sync. The follow-up PR replaces that with a single resolved profile state (`ResolvedPermissionProfile` / `PermissionProfileState`) that keeps the profile id, immutable `PermissionProfile`, and profile-declared workspace roots together. That follow-up removes APIs such as `set_constrained_permission_profile_with_active_profile()` where separate arguments could drift out of sync. Downstream PRs then build on this base to switch app-server turn updates to profile ids plus runtime workspace roots and to finish the user-visible summary behavior. Reviewers should judge this PR as the workspace-roots foundation, not as the final in-memory shape of selected permission profiles. ## Review Guide Suggested review order: 1. Start with `codex-rs/core/src/config/mod.rs`. This is the main shape change in the base slice. `Permissions` now stores a private raw `Constrained<PermissionProfile>` plus runtime `workspace_roots`. Callers use `permission_profile()` when they need the raw constrained value and `effective_permission_profile()` when they need a materialized runtime profile. As noted above, [#22683](https://github.com/openai/codex/pull/22683) replaces this transitional shape with a resolved profile state that keeps identity and profile data together. 2. Review `codex-rs/config/src/permissions_toml.rs` and `codex-rs/core/src/config/permissions.rs`. These add `[permissions.<id>.workspace_roots]`, resolve enabled entries relative to the policy cwd, and keep `:workspace_roots` deny-read glob patterns symbolic until the actual roots are known. 3. Review `codex-rs/protocol/src/permissions.rs` and `codex-rs/protocol/src/models.rs`. These add the policy/profile materialization helpers that expand exact `:workspace_roots` entries and scoped deny-read globs over every workspace root. This is also where `ActivePermissionProfileModification` is removed from the core model. 4. Review the legacy bridge in `Config::load_from_base_config_with_overrides` and `Config::set_legacy_sandbox_policy`. This is where legacy `workspace-write` roots become runtime workspace roots, while Codex internal writable roots stay internal and do not appear as user-facing workspace roots. 5. Then skim downstream call sites. The interesting pattern is raw-vs-effective access: state/proxy/bwrap paths keep the raw constrained profile, while execution, summaries, and user-visible status use the effective profile and workspace-root list. ## What Changed - added `[permissions.<id>.workspace_roots]` to the config model and schema - added runtime `workspace_roots` state to `Config`/`Permissions` and `ConfigOverrides` - made `Permissions` profile fields private and replaced direct mutation with accessors/setters - added `PermissionProfile` and `FileSystemSandboxPolicy` helpers for materializing `:workspace_roots` exact paths and deny-read globs across all roots - moved legacy additional writable roots into runtime workspace-root state instead of active profile modifications - removed `ActivePermissionProfileModification` and its app-server protocol/schema export - updated sandbox/status summary paths so internal writable roots are not reported as user workspace roots ## Verification Strategy The targeted tests cover the behavior at the layers where regressions are most likely: - `codex-rs/core/src/config/config_tests.rs` verifies config loading, legacy workspace-root seeding, effective profile materialization, and memory-root handling. - `codex-rs/core/src/config/permissions_tests.rs` verifies profile `workspace_roots` parsing and `:workspace_roots` scoped/glob compilation. - `codex-rs/protocol/src/permissions.rs` unit tests verify exact and glob materialization over multiple workspace roots. - `codex-rs/tui/src/status/tests.rs` and `codex-rs/utils/sandbox-summary/src/sandbox_summary.rs` verify the user-facing summaries show effective workspace roots and hide internal writes. I also ran `cargo check --tests` locally after the latest stack refresh to catch cross-crate API breakage from the private-field/accessor changes. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22610). * #22612 * #22611 * #22683 * __->__ #22610
Michael Bolin ·
2026-05-14 18:25:23 -07:00 -
[codex] Remove experimental instructions file config (#22724)
## Summary Remove the deprecated `experimental_instructions_file` config setting from the typed config surface and the remaining deprecation-notice plumbing. `model_instructions_file` remains the supported setting and its loading path is unchanged. The setting was deprecated when it was renamed to `model_instructions_file` on January 20, 2026 in https://github.com/openai/codex/pull/9555. ## Changes - Remove `experimental_instructions_file` from `ConfigToml` and `ConfigProfile`. - Delete the custom config-layer scan and session deprecation notice for the removed setting. - Stop clearing the removed field from generated session config locks. - Remove the obsolete deprecation-notice test case while keeping `model_instructions_file` coverage intact. ## Validation - `just write-config-schema` - `just fmt` - `cargo test -p codex-config` - `cargo test -p codex-core model_instructions_file` - `just fix -p codex-core` - `git diff --check` Co-authored-by: Codex <noreply@openai.com>
Dylan Hurd ·
2026-05-14 18:04:26 -07:00