Commit Graph

1542 Commits

  • fix(tui): conditionally restore status indicator using message phase (#10947)
    TLDR: use new message phase field emitted by preamble-supported models
    to determine whether an AgentMessage is mid-turn commentary. if so,
    restore the status indicator afterwards to indicate the turn has not
    completed.
    
    ### Problem
    `commit_tick` hides the status indicator while streaming assistant text.
    For preamble-capable models, that text can be commentary mid-turn, so
    hiding was correct during streaming but restore timing mattered:
    - restoring too aggressively caused jitter/flashing
    - not restoring caused indicator to stay hidden before subsequent work
    (tool calls, web search, etc.)
    
    ### Fix
    - Add optional `phase` to `AgentMessageItem` and propagate it from
    `ResponseItem::Message`
    - Keep indicator hidden during streamed commit ticks, restore only when:
      - assistant item completes as `phase=commentary`, and
      - stream queues are idle + task is still running.
    - Treat `phase=None` as final-answer behavior (no restore) to keep
    existing behavior for non-preamble models
    
    ### Tests
    Add/update tests for:
    - no idle-tick restore without commentary completion
    - commentary completion restoring status before tool begin
    - snapshot coverage for preamble/status behavior
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • TUI/Core: preserve duplicate skill/app mention selection across submit + resume (#10855)
    ## What changed
    
    - In `codex-rs/core/src/skills/injection.rs`, we now honor explicit
    `UserInput::Skill { name, path }` first, then fall back to text mentions
    only when safe.
    - In `codex-rs/tui/src/bottom_pane/chat_composer.rs`, mention selection
    is now token-bound (selected mention is tied to the specific inserted
    `$token`), and we snapshot bindings at submit time so selection is not
    lost.
    - In `codex-rs/tui/src/chatwidget.rs` and
    `codex-rs/tui/src/bottom_pane/mod.rs`, submit/queue paths now consume
    the submit-time mention snapshot (instead of rereading cleared composer
    state).
    - In `codex-rs/tui/src/mention_codec.rs` and
    `codex-rs/tui/src/bottom_pane/chat_composer_history.rs`, history now
    round-trips mention targets so resume restores the same selected
    duplicate.
    - In `codex-rs/tui/src/bottom_pane/skill_popup.rs` and
    `codex-rs/tui/src/bottom_pane/chat_composer.rs`, duplicate labels are
    normalized to `[Repo]` / `[App]`, app rows no longer show `Connected -`,
    and description space is a bit wider.
    
    <img width="550" height="163" alt="Screenshot 2026-02-05 at 9 56 56 PM"
    src="https://github.com/user-attachments/assets/346a7eb2-a342-4a49-aec8-68dfec0c7d89"
    />
    <img width="550" height="163" alt="Screenshot 2026-02-05 at 9 57 09 PM"
    src="https://github.com/user-attachments/assets/5e04d9af-cccf-4932-98b3-c37183e445ed"
    />
    
    
    ## Before vs now
    
    - Before: selecting a duplicate could still submit the default/repo
    match, and resume could lose which duplicate was originally selected.
    - Now: the exact selected target (skill path or app id) is preserved
    through submit, queue/restore, and resume.
    
    ## Manual test
    
    1. Build and run this branch locally:
       - `cd /Users/daniels/code/codex/codex-rs`
       - `cargo build -p codex-cli --bin codex`
       - `./target/debug/codex`
    2. Open mention picker with `$` and pick a duplicate entry (not the
    first one).
    3. Confirm duplicate UI:
       - repo duplicate rows show `[Repo]`
       - app duplicate rows show `[App]`
       - app description does **not** start with `Connected -`
    4. Submit the prompt, then press Up to restore draft and submit again.  
       Expected: it keeps the same selected duplicate target.
    5. Use `/resume` to reopen the session and send again.  
    Expected: restored mention still resolves to the same duplicate target.
  • Support alternative websocket API (#10861)
    **Test plan**
    
    ```
    cargo build -p codex-cli && RUST_LOG='codex_api::endpoint::responses_websocket=trace,codex_core::client=debug,codex_core::codex=debug' \
      ./target/debug/codex \
        --enable responses_websockets_v2 \
        --profile byok \
        --full-auto
    ```
  • Treat compaction failure as failure state (#10927)
    - Return compaction errors from local and remote compaction flows.\n-
    Stop turns/tasks when auto-compaction fails instead of continuing
    execution.
  • core: refresh developer instructions after compaction replacement history (#10574)
    ## Summary
    
    When replaying compacted history (especially `replacement_history` from
    remote compaction), we should not keep stale developer messages from
    older session state. This PR trims developer-
    role messages from compacted replacement history and reinjects fresh
    developer instructions derived from current turn/session state.
    
    This aligns compaction replay behavior with the intended "fresh
    instructions after summary" model.
    
    ## Problem
    
    Compaction replay had two paths:
    
    - `Compacted { replacement_history: None }`: rebuilt with fresh initial
    context
    - `Compacted { replacement_history: Some(...) }`: previously used raw
    replacement history as-is
    
    The second path could carry stale developer instructions
    (permissions/personality/collab-mode guidance) across session changes.
    
    ## What Changed
    
    ### 1) Added helper to refresh compacted developer instructions
    
    - **File:** `codex-rs/core/src/compact.rs`
    - **Function:** `refresh_compacted_developer_instructions(...)`
    
    Behavior:
    - remove all `ResponseItem::Message { role: "developer", .. }` from
    compacted history
    - append fresh developer messages from current
    `build_initial_context(...)`
    
    ### 2) Applied helper in remote compaction flow
    
    - **File:** `codex-rs/core/src/compact_remote.rs`
    - After receiving compact endpoint output, refresh developer
    instructions before replacing history and persisting
    `replacement_history`.
    
    ### 3) Applied helper while reconstructing history from rollout
    
    - **File:** `codex-rs/core/src/codex.rs`
    - In `reconstruct_history_from_rollout(...)`, when processing
    `Compacted` entries with `replacement_history`, refresh developer
    instructions instead of directly replacing with raw history.
    
    ## Non-Goals / Follow-up
    
    This PR does **not** address the existing first-turn-after-resume
    double-injection behavior.
    A follow-up PR will handle resume-time dedup/idempotence separately.
    
    If you want, I can also give you a shorter “squash-merge friendly”
    version of the description.
    
    ## Codex author
    `codex fork 019c25e6-706e-75d1-9198-688ec00a8256`
  • core: preconnect Responses websocket for first turn (#10698)
    ## Problem
    The first user turn can pay websocket handshake latency even when a
    session has already started. We want to reduce that initial delay while
    preserving turn semantics and avoiding any prompt send during startup.
    
    Reviewer feedback also called out duplicated connect/setup paths and
    unnecessary preconnect state complexity.
    
    ## Mental model
    `ModelClient` owns session-scoped transport state. During session
    startup, it can opportunistically warm one websocket handshake slot. A
    turn-scoped `ModelClientSession` adopts that slot once if available,
    restores captured sticky turn-state, and otherwise opens a websocket
    through the same shared connect path.
    
    If startup preconnect is still in flight, first turn setup awaits that
    task and treats it as the first connection attempt for the turn.
    
    Preconnect is handshake-only. The first `response.create` is still sent
    only when a turn starts.
    
    ## Non-goals
    This change does not make preconnect required for correctness and does
    not change prompt/turn payload semantics. It also does not expand
    fallback behavior beyond clearing preconnect state when fallback
    activates.
    
    ## Tradeoffs
    The implementation prioritizes simpler ownership and shared connection
    code over header-match gating for reuse. The single-slot cache keeps
    lifecycle straightforward but only benefits the immediate next turn.
    
    Awaiting in-flight preconnect has the same app-level connect-timeout
    semantics as existing websocket connect behavior (no new timeout class
    introduced by this PR).
    
    ## Architecture
    `core/src/client.rs`:
    - Added session-level preconnect lifecycle state (`Idle` / `InFlight` /
    `Ready`) carrying one warmed websocket plus optional captured
    turn-state.
    - Added `pre_establish_connection()` startup warmup and `preconnect()`
    handshake-only setup.
    - Deduped auth/provider resolution into `current_client_setup()` and
    websocket handshake wiring into `connect_websocket()` /
    `build_websocket_headers()`.
    - Updated turn websocket path to adopt preconnect first, await in-flight
    preconnect when present, then create a new websocket only when needed.
    - Ensured fallback activation clears warmed preconnect state.
    - Added documentation for lifecycle, ownership, sticky-routing
    invariants, and timeout semantics.
    
    `core/src/codex.rs`:
    - Session startup invokes `model_client.pre_establish_connection(...)`.
    - Turn metadata resolution uses the shared timeout helper.
    
    `core/src/turn_metadata.rs`:
    - Centralized shared timeout helper used by both turn-time metadata
    resolution and startup preconnect metadata building.
    
    `core/tests/common/responses.rs` + websocket test suites:
    - Added deterministic handshake waiting helper (`wait_for_handshakes`)
    with bounded polling.
    - Added startup preconnect and in-flight preconnect reuse coverage.
    - Fallback expectations now assert exactly two websocket attempts in
    covered scenarios (startup preconnect + turn attempt before fallback
    sticks).
    
    ## Observability
    Preconnect remains best-effort and non-fatal. Existing
    websocket/fallback telemetry remains in place, and debug logs now make
    preconnect-await behavior and preconnect failures easier to reason
    about.
    
    ## Tests
    Validated with:
    1. `just fmt`
    2. `cargo test -p codex-core websocket_preconnect -- --nocapture`
    3. `cargo test -p codex-core websocket_fallback -- --nocapture`
    4. `cargo test -p codex-core
    websocket_first_turn_waits_for_inflight_preconnect -- --nocapture`
  • Add app configs to config.toml (#10822)
    Adds app configs to config.toml + tests
  • Removed "exec_policy" feature flag (#10851)
    This is no longer needed because it's on by default
  • Handle required MCP startup failures across components (#10902)
    Summary
    - add a `required` flag for MCP servers everywhere config/CLI data is
    touched so mandatory helpers can be round-tripped
    - have `codex exec` and `codex app-server` thread start/resume fail fast
    when required MCPs fail to initialize
  • Print warning when config does not meet requirements (#10792)
    <img width="1019" height="284" alt="Screenshot 2026-02-05 at 23 34 08"
    src="https://github.com/user-attachments/assets/19ec3ce1-3c3b-40f5-b251-a31d964bf3bb"
    />
    
    Currently, if a config value is set that fails the requirements, we exit
    Codex.
    
    Now, instead of this, we print a warning and default to a
    requirements-permitting value.
  • feat(app-server): turn/steer API (#10821)
    This PR adds a dedicated `turn/steer` API for appending user input to an
    in-flight turn.
    
    ## Motivation
    Currently, steering in the app is implemented by just calling
    `turn/start` while a turn is running. This has some really weird quirks:
    - Client gets back a new `turn.id`, even though streamed
    events/approvals remained tied to the original active turn ID.
    - All the various turn-level override params on `turn/start` do not
    apply to the "steer", and would only apply to the next real turn.
    - There can also be a race condition where the client thinks the turn is
    active but the server has already completed it, so there might be bugs
    if the client has baked in some client-specific behavior thinking it's a
    steer when in fact the server kicked off a new turn. This is
    particularly possible when running a client against a remote app-server.
    
    Having a dedicated `turn/steer` API eliminates all those quirks.
    
    `turn/steer` behavior:
    - Requires an active turn on threadId. Returns a JSON-RPC error if there
    is no active turn.
    - If expectedTurnId is provided, it must match the active turn (more
    useful when connecting to a remote app-server).
    - Does not emit `turn/started`.
    - Does not accept turn overrides (`cwd`, `model`, `sandbox`, etc.) or
    `outputSchema` to accurately reflect that these are not applied when
    steering.
  • go back to auto-enabling web_search for azure (#10820)
    ###### What
    Remove special-casing that prevented auto-enabling `web_search` for
    Azure model provider users. Addresses #10071, #10257.
    
    ###### Why
    Azure fixed their responsesapi implementation; `web_search` is now
    supported on models it wasn't before (like `gpt-5.1-codex-max`).
    
    This request now works:
    ```
    curl "$AZURE_API_ENDPOINT" -H "Content-Type: application/json" -H "Authorization: Bearer $AZURE_API_KEY" -d '{
      "model": "gpt-5.1-codex-max",
      "tools": [
        { "type": "web_search" }
      ],
      "tool_choice": "auto",
      "input": "Find the sunrise time in Paris today and cite the source."
    }'
    ```
    
    ###### Tests
    Tested with above curl, removed Azure-specific tests.
  • chore: rm web-search-eligible header (#10660)
    default-enablement of web_search is now client-side, no need to send
    eligibility headers to backend.
    
    Tested locally, headers no longer sent.
    
    will wait for corresponding backend change to deploy before merging
  • add sandbox policy and sandbox name to codex.tool.call metrics (#10711)
    This will give visibility into the comparative success rate of the
    Windows sandbox implementations compared to other platforms.
  • fix(auth): isolate chatgptAuthTokens concept to auth manager and app-server (#10423)
    So that the rest of the codebase (like TUI) don't need to be concerned
    whether ChatGPT auth was handled by Codex itself or passed in via
    app-server's external auth mode.
  • feat(tui): add /statusline command for interactive status line configuration (#10546)
    ## Summary
    - Adds a new `/statusline` command to configure TUI footer status line
    - Introduces reusable `MultiSelectPicker` component with keyboard
    navigation, optional ordering and toggle support
    - Implement status line setup modal that persist configuration to
    config.toml
    
      ## Status Line Items
      The following items can be displayed in the status line:
      - **Model**: Current model name (with optional reasoning level)
      - **Context**: Remaining/used context window percentage
      - **Rate Limits**: 5-day and weekly usage limits
      - **Git**: Current branch (with optimized lookups)
      - **Tokens**: Used tokens, input/output token counts
      - **Session**: Session ID (full or shortened prefix)
      - **Paths**: Current directory, project root
      - **Version**: Codex version
    
      ## Features
      - Live preview while configuring status line items
      - Fuzzy search filtering in the picker
      - Intelligent truncation when items don't fit
      - Items gracefully omit when data is unavailable
      - Configuration persists to `config.toml`
      - Validates and warns about invalid status line items
    
      ## Test plan
      - [x] Run `/statusline` and verify picker UI appears
      - [x] Toggle items on/off and verify live preview updates
      - [x] Confirm selection persists after restart
      - [x] Verify truncation behavior with many items selected
      - [x] Test git branch detection in and out of git repos
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Add hooks implementation and wire up to notify (#9691)
    This introduces a `Hooks` service. It registers hooks from config and
    dispatches hook events at runtime.
    
    N.B. The hook config is not wired up to this yet. But for legacy
    reasons, we wire up `notify` from config and power it using hooks now.
    Nothing about the `notify` interface has changed.
    
    I'd start by reviewing `hooks/types.rs`
    
    Some things to note:
      - hook names subject to change
      - no hook result yet
      - stopping semantics yet to be introduced
      - additional hooks yet to be introduced
  • Leverage state DB metadata for thread summaries (#10621)
    Summary:
    - read conversation summaries and cwd info from the state DB when
    possible so we no longer rely on rollout files for metadata and avoid
    extra I/O
    - persist CLI version in thread metadata, surface it through summary
    builders, and add the necessary DB migration hooks
    - simplify thread listing by using enriched state DB data directly
    rather than reading rollout heads
    
    Testing:
    - Not run (not requested)
  • feat: add memory tool (#10637)
    Add a tool for memory to retrieve a full memory based on the memory ID
  • feat: resumable backfill (#10745)
    ## Summary
    
    This PR makes SQLite rollout backfill resumable and repeatable instead
    of one-shot-on-db-create.
    
    ## What changed
    
    - Added a persisted backfill state table:
      - state/migrations/0008_backfill_state.sql
    - Tracks status (pending|running|complete), last_watermark, and
    last_success_at.
    - Added backfill state model/types in codex-state:
      - BackfillState, BackfillStatus (state/src/model/backfill_state.rs)
    - Added runtime APIs to manage backfill lifecycle/progress:
      - get_backfill_state
      - mark_backfill_running
      - checkpoint_backfill
      - mark_backfill_complete
    - Updated core startup behavior:
    - Backfill now runs whenever state is not Complete (not only when DB
    file is newly created).
    - Reworked backfill execution:
    - Collect rollout files, derive deterministic watermark per path, sort,
    resume from last_watermark.
    - Process in batches (BACKFILL_BATCH_SIZE = 200), checkpoint after each
    batch.
      - Mark complete with last_success_at at the end.
    
    ## Why
    
    Previous behavior could leave users permanently partially backfilled if
    the process exited during initial async backfill. This change allows
    safe continuation across restarts and avoids restarting from scratch.
  • Update explorer role default model (#10748)
    Summary
    - switch the explorer role in core agent configuration to use
    `gpt-5.1-codex-mini` as the default model override
    - leave other role defaults untouched
    
    Testing
    - Not run (not requested)
  • adding fork information (UI) when forking (#10246)
    - shows `/fork` command that ran in prev session
    - shows `session forked from name (uuid) || uuid (if name is not set)` as an event in new session
  • Allow user shell commands to run alongside active turns (#10513)
    Summary
    - refactor user shell command execution into a shared helper and add
    modes for standalone vs active-turn execution
    - run user shell commands asynchronously when a turn is already active
    so they don’t replace or abort the current turn
    - extend the tests to cover the new behavior and add the generated Codex
    environment manifest
    
    Testing
    - Not run (not requested)
  • fix(core,app-server) resume with different model (#10719)
    ## Summary
    When resuming with a different model, we should also append a developer
    message with the model instructions
    
    ## Testing
    - [x] Added unit tests
  • Fix remote compaction estimator/payload instruction small mismatch (#10692)
    ## Summary
    This PR fixes a deterministic mismatch in remote compaction where
    pre-trim estimation and the `/v1/responses/compact` payload could use
    different base instructions.
    
    Before this change:
    - pre-trim estimation used model-derived instructions
    (`model_info.get_model_instructions(...)`)
    - compact payload used session base instructions
    (`sess.get_base_instructions()`)
    
    After this change:
    - remote pre-trim estimation and compact payload both use the same
    `BaseInstructions` instance from session state.
    
    ## Changes
    - Added a shared estimator entry point in `ContextManager`:
    - `estimate_token_count_with_base_instructions(&self, base_instructions:
    &BaseInstructions) -> Option<i64>`
    - Kept `estimate_token_count(&TurnContext)` as a thin wrapper that
    resolves model/personality instructions and delegates to the new helper.
    - Updated remote compaction flow to fetch base instructions once and
    reuse it for both:
      - trim preflight estimation
      - compact request payload construction
    - Added regression coverage for parity and behavior:
      - unit test verifying explicit-base estimator behavior
    - integration test proving remote compaction uses session override
    instructions and trims accordingly
    
    ## Why this matters
    This removes a deterministic divergence source where pre-trim could
    think the request fits while the actual compact request exceeded context
    because its instructions were longer/different.
    
    ## Scope
    In scope:
    - estimator/payload base-instructions parity in remote compaction
    
    Out of scope:
    - retry-on-`context_length_exceeded`
    - compaction threshold/headroom policy changes
    - broader trimming policy changes
    
    ## Codex author:
    `codex fork 019c2b24-c2df-7b31-a482-fb8cf7a28559`
  • Make steer stable by default (#10690)
    Promotes the Steer feature from Experimental to Stable and enables it by
    default.
    
    ## What is Steer mode?
    
    Steer mode changes how message submission works in the TUI:
    
    - **With Steer enabled (new default)**: 
      - `Enter` submits messages immediately, even when a task is running
    - `Tab` queues messages when a task is running (allows building up a
    queue)
      
    - **With Steer disabled (old behavior)**:
      - `Enter` queues messages when a task is running
      - This preserves the previous "queue while a task is running" behavior
    
    ## How Steer vs Queue work
    
    The key difference is in the submission behavior:
    
    1. **Steer mode** (`steer_enabled = true`):
    - Enter → `InputResult::Submitted` → sends immediately via
    `submit_user_message()`
    - Tab → `InputResult::Queued` → queues via `queue_user_message()` if a
    task is running
    - This gives users direct control: Enter for immediate submission, Tab
    for queuing
    
    2. **Queue mode** (`steer_enabled = false`, previous default):
    - Enter → `InputResult::Queued` → always queues when a task is running
       - Tab → `InputResult::Queued` → queues when a task is running
    - This preserves the original behavior where Enter respects the running
    task queue
    
    ## Implementation details
    
    The behavior is controlled in
    `ChatComposer::handle_key_event_without_popup()`:
    - When `steer_enabled` is true, Enter calls `handle_submission(false)`
    (submit immediately)
    - When `steer_enabled` is false, Enter calls `handle_submission(true)`
    (queue)
    
    See `codex-rs/tui/src/bottom_pane/chat_composer.rs` for the
    implementation.
    
    ## Documentation
    
    For more details on the chat composer behavior, see:
    - [TUI Chat Composer documentation](docs/tui-chat-composer.md)
    - Feature flag definition: `codex-rs/core/src/features.rs`
  • Sync collaboration mode naming across Default prompt, tools, and TUI (#10666)
    ## Summary
    - add shared `ModeKind` helpers for display names, TUI visibility, and
    `request_user_input` availability
    - derive TUI mode filtering/labels from shared `ModeKind` metadata
    instead of local hardcoded matches
    - derive `request_user_input` availability text and unavailable error
    mode names from shared mode metadata
    - replace hardcoded known mode names in the Default collaboration-mode
    template with `{{KNOWN_MODE_NAMES}}` and fill it from
    `TUI_VISIBLE_COLLABORATION_MODES`
    - add regression tests for mode metadata sync and placeholder
    replacement
    
    ## Notes
    - `cargo test -p codex-core` integration target (`tests/all`) still
    shows pre-existing env-specific failures in this environment due missing
    `test_stdio_server` binary resolution; core unit tests are green.
    
    ## Codex author
    `codex resume 019c26ff-dfe7-7173-bc04-c9e1fff1e447`
  • fix(core) switching model appends model instructions (#10651)
    ## Summary
    When switching models, we should append the instructions of the new
    model to the conversation as a developer message.
    
    ## Test
    - [x] Adds a unit test
  • chore(config) Default Personality Pragmatic (#10705)
    ## Summary
    Switch back to Pragmatic personality
    
    ## Testing
    - [x] Updated unit tests
  • chore(core) personality migration tests (#10650)
    ## Summary
    Adds additional tests for personality edge cases
    
    ## Testing
    - [x] These are tests
  • Cloud Requirements: increase timeout and retries (#10631)
    Add retries and an increased-length timeout for loading Cloud
    Requirements.
    
    Co-authored-by: alexsong-oai <alexsong@openai.com>
  • feat(core): add configurable log_dir (#10678)
    Adds a top-level `log_dir` config key (defaults to `$CODEX_HOME/log`) so
    one-off runs can redirect `codex-tui.log` via `-c`, e.g.:
    
      codex -c log_dir=./.codex-log
    
    Also resolves relative paths in CLI `-c/--config` overrides for
    `AbsolutePathBuf` values against the effective cwd (when available).
    
    Tests:
    - cargo test -p codex-core
  • Session-level model client (#10664)
    Make ModelClient a session-scoped object.
    Move state that is session level onto the client, and make state that is
    per-turn explicit on corresponding methods.
    Stop taking a huge Config object, instead only pass in values that are
    actually needed.
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • feat(app-server, core): allow text + image content items for dynamic tool outputs (#10567)
    Took over the work that @aaronl-openai started here:
    https://github.com/openai/codex/pull/10397
    
    Now that app-server clients are able to set up custom tools (called
    `dynamic_tools` in app-server), we should expose a way for clients to
    pass in not just text, but also image outputs. This is something the
    Responses API already supports for function call outputs, where you can
    pass in either a string or an array of content outputs (text, image,
    file):
    https://platform.openai.com/docs/api-reference/responses/create#responses_create-input-input_item_list-item-function_tool_call_output-output-array-input_image
    
    So let's just plumb it through in Codex (with the caveat that we only
    support text and image for now). This is implemented end-to-end across
    app-server v2 protocol types and core tool handling.
    
    ## Breaking API change
    NOTE: This introduces a breaking change with dynamic tools, but I think
    it's ok since this concept was only recently introduced
    (https://github.com/openai/codex/pull/9539) and it's better to get the
    API contract correct. I don't think there are any real consumers of this
    yet (not even the Codex App).
    
    Old shape:
    `{ "output": "dynamic-ok", "success": true }`
    
    New shape:
    ```
    {
        "contentItems": [
          { "type": "inputText", "text": "dynamic-ok" },
          { "type": "inputImage", "imageUrl": "data:image/png;base64,AAA" }
        ]
      "success": true
    }
    ```
  • add none personality option (#10688)
    - add none personality enum value and empty placeholder behavior\n- add
    docs/schema updates and e2e coverage
  • Added support for live updates to skills (#10478)
    Add a centralized FileWatcher in codex-core (using notify) that watches
    skill roots from the config layer stack (recursive)
    
    Send `SkillsChanged` events when relevant file system changes are
    detected
    
    On `SkillsChanged`:
    * Invalidate the skills cache immediately in ThreadManager
    * Emit EventMsg::SkillsUpdateAvailable to active sessions
    ~~* Broadcast a new app-server notification:
    SkillsListUpdatedNotification~~
    
    This change does not inject new items into the event stream. That means
    the agent will not know about new skills, so it won't be able to
    implicitly invoke new skills. It also won't know about changes to
    existing skills, so if it has already read the contents of a modified
    skill, it will not honor the new behavior.
    
    This change also does not detect modifications to AGENTS.md.
    
    I plan to address these limitations in a follow-on PR modeled after
    #9985. Injection of new skills and AGENTS was deemed to risky, hence the
    need to split the feature into two stages. The changes in this PR were
    designed to easily accommodate the second stage once we have some other
    foundational changes in place.
    
    Testing: In addition to automated tests, I did manual testing to confirm
    that newly-created skills, deleted skills, and renamed skills are
    reflected in the TUI skill picker menu. Also confirmed that
    modifications to behaviors for explicitly-invoked skills are honored.
    
    ---------
    
    Co-authored-by: Xin Lin <xl@openai.com>
  • [apps] Cache MCP actions from apps. (#10662)
    MCP actions take a long time to load for users with lots of apps
    installed. Adding a cache for these actions with 1hr expiration, given
    that they are almost always aren't going to change unless people install
    another app, which means they also need to restart codex to pick it up.
  • feat: add phase 1 mem db (#10634)
    - Schema: thread_id (PK, FK to threads.id with cascade delete),
    trace_summary, memory_summary, updated_at.
    - Migration: creates the table and an index on (updated_at DESC,
    thread_id DESC) for efficient recent-first reads.
      - Runtime API (DB-only):
          - `get_thread_memory(thread_id)`: fetch one memory row.
    - `upsert_thread_memory(thread_id, trace_summary, memory_summary)`:
    insert/update by thread id and always advance updated_at.
    - `get_last_n_thread_memories_for_cwd(cwd, n)`: join thread_memory with
    threads and return newest n rows for an exact cwd match.
    - Model layer: introduced ThreadMemory and row conversion types to keep
    query decoding typed and consistent with existing state models.
  • Persist pending input user events (#10656)
    - Persist user-message events for mid-turn injected input by emitting
    user message turn items when pending input is recorded.