Commit Graph

3425 Commits

  • [codex] nest sleep config under current time reminder (#29910)
    ## Summary
    
    - move sleep tool enablement from top-level `[features].sleep_tool` to
    `[features.current_time_reminder].sleep_tool`
    - remove the standalone `Feature::SleepTool` flag and gate `clock.sleep`
    from resolved current-time configuration
    - update config schema, config-lock materialization, and existing sleep
    coverage
    
    Stacked on #29907.
  • [codex] namespace sleep under clock (#29907)
    ## Summary
    
    - expose the interruptible sleep tool as `clock.sleep` instead of
    top-level `sleep`
    - keep `clock.curr_time` and `clock.sleep` in the same model-visible
    namespace when both features are enabled
    - update existing core and app-server integration coverage to issue
    namespaced sleep calls
    
    ## Why
    
    Sleep is a clock operation. Grouping it with `clock.curr_time` gives the
    model a more coherent tool surface without changing the sleep feature
    gate or runtime behavior.
    
    ## Validation
    
    - `just test -p codex-core sleep_tool_follows_feature_gate`
    - `just test -p codex-core any_new_input_interrupts_sleep`
    - `just test -p codex-app-server
    sleep_emits_started_and_completed_items`
  • Add a connector declaration snapshot (#29851)
    ## Why
    
    Connector declarations currently enter Codex through broad plugin
    capability summaries, then MCP setup, turn tooling, and `app/list` each
    reconstruct the same information. That makes executor-selected
    connectors difficult to add without coupling connector behavior to the
    host plugin loader.
    
    This PR introduces a small connector-owned value that later stack layers
    can populate before thread startup.
    
    ## What changed
    
    - Move the pure app-declaration parser into `codex-connectors`,
    preserving declaration order and category cleanup while leaving
    host-side validation and deduplication unchanged.
    - Add an immutable `ConnectorSnapshot` with ordered connector IDs and
    plugin display-name provenance.
    - Adapt the existing local-plugin capability summaries into that
    snapshot at current consumer boundaries.
    - Use the snapshot for MCP tool provenance, turn connector inventory,
    and `app/list`.
    - Keep the crate API narrow: no test-only snapshot accessors are
    exposed.
    
    The externally visible behavior is unchanged. Connector tools still come
    from the orchestrator-owned `/ps/mcp` server, and local plugin
    enablement remains owned by the existing plugin loader.
    
    ## Stack scope
    
    This is the foundation only. It does not read selected executor packages
    or change thread startup. #29852 adds the executor-backed declaration
    reader, and #29856 composes selected declarations into a thread
    snapshot.
  • Pipeline bounded AGENTS.md and Git root probes (#29870)
    ## Why
    
    When Codex uses a remote `ExecutorFileSystem`, every `get_metadata` call
    is an exec-server round trip. Upward discovery currently pays those
    round trips serially in two latency-sensitive places:
    
    - session startup, while locating the configured project root before
    loading `AGENTS.md`; and
    - Git-root discovery, which runs before per-turn Git diff enrichment.
    
    The goal is to remove the serial ancestor dependency without adding a
    new filesystem RPC, JSON-RPC batch method, Git executable dependency, or
    cache.
    
    ## Example
    
    Assume this layout, with `.git` as the configured project-root marker:
    
    ```text
    /workspace/repo/.git
    /workspace/repo/AGENTS.md
    /workspace/repo/crates/core/    <- cwd
    ```
    
    The marker probes have this required precedence:
    
    ```text
    1. /workspace/repo/crates/core/.git
    2. /workspace/repo/crates/.git
    3. /workspace/repo/.git
    4. /workspace/.git
    5. /.git
    ```
    
    Previously, probe 2 was not sent until probe 1 returned, and probe 3 was
    not sent until probe 2 returned. With this change, the client lazily
    keeps up to eight ordinary `fs/getMetadata` requests in flight, but
    consumes their results in the order above. Codex must still learn that
    probes 1 and 2 are absent before accepting probe 3, so the nearest root
    always wins. Once probe 3 succeeds, the client has its answer and stops
    awaiting probes 4 and 5. Requests that were already sent may still
    finish on the worker.
    
    For the marker phase alone, with a 50 ms client-to-worker round trip and
    fast local metadata calls, finding the root at probe 3 changes from
    roughly three serialized round trips (150 ms) to one round trip plus
    worker processing. The later `AGENTS.md` candidate phase remains
    separate and ordered.
    
    Only after `/workspace/repo` is selected does `AGENTS.md` discovery
    check instruction candidates, in root-to-cwd order:
    
    ```text
    /workspace/repo/AGENTS.override.md
    /workspace/repo/AGENTS.md
    /workspace/repo/crates/AGENTS.override.md
    /workspace/repo/crates/AGENTS.md
    /workspace/repo/crates/core/AGENTS.override.md
    /workspace/repo/crates/core/AGENTS.md
    ```
    
    The first configured candidate found in each directory wins. These
    checks remain ordered and no instruction candidate above
    `/workspace/repo` is issued. Git-root discovery uses the same bounded
    lookup with only `.git` as the marker.
    
    ## What changed
    
    - Added a client-side find-up helper that generates `ancestor x marker`
    probes lazily, nearest directory first and configured marker order
    within each directory.
    - Uses an ordered concurrency window of eight scalar metadata requests.
    This bounds executor load while preserving nearest-root and marker
    precedence.
    - Reuses the helper for both configured project-root discovery and
    remote Git-root discovery.
    - Keeps Git ancestor and marker construction in `AbsolutePathBuf`,
    converting only each complete `.git` probe to `PathUri`. This preserves
    native paths that require an opaque URI fallback, such as Windows
    namespace paths.
    - Preserves existing error behavior: `AGENTS.md` discovery propagates
    non-`NotFound` metadata errors, while Git discovery treats a failed
    marker probe as absent and continues upward.
    - Reads each discovered `AGENTS.md` directly instead of statting it a
    second time.
    
    No filesystem trait or exec-server protocol method is added. An empty
    `project_root_markers` list performs no ancestor-marker I/O and checks
    instruction candidates only in `cwd`. This change also deliberately does
    not cache roots across turns.
    
    ## Symlinks
    
    Upward traversal remains **lexical**. The helper does not canonicalize
    `cwd`; it appends marker names to the supplied path and walks that
    path's textual parents. The filesystem performs the actual metadata/read
    operation, and the current local and exec-server implementations follow
    live symlink targets.
    
    For example:
    
    ```text
    /tmp/pkg -> /workspace/repo/packages/pkg
    cwd = /tmp/pkg/src
    actual Git marker = /workspace/repo/.git
    ```
    
    The lexical probes are `/tmp/pkg/src/.git`, `/tmp/pkg/.git`,
    `/tmp/.git`, and `/.git`. They do not jump from `/tmp/pkg` to the
    target's parent `/workspace/repo`, so this spelling of `cwd` does not
    discover `/workspace/repo/.git`. That is the existing behavior and is
    unchanged by this PR.
    
    Conversely, if `/tmp/repo -> /workspace/repo`, then probing
    `/tmp/repo/.git` follows the directory symlink and finds
    `/workspace/repo/.git`; the reported root remains the lexical path
    `/tmp/repo`. A live symlink used directly as `.git`, another configured
    marker, or `AGENTS.md` is also followed. A symlinked `AGENTS.md` is
    loaded when its target is a regular file, while a broken symlink behaves
    as `NotFound`.
  • [plugins] Track plugin install requests by ID (#29684)
    Summary
    - Emit `codex_plugin_install_requested` when a validated plugin install
    request is made, before the user accepts or declines the elicitation.
    - Record the exact model-visible plugin ID, remote plugin ID, required
    connector IDs, stable suggestion ID, and `endpoint_recommendation` vs
    `legacy_discovery` source.
    - Keep `suggest_reason` out of telemetry and leave connector-only
    install requests unchanged.
    
    Rollout
    - Backend/schema dependency:
    https://github.com/openai/openai/pull/1065270
    - Land the backend PR before this producer starts sending the event.
    
    Validation
    - `just test -p codex-analytics` (83 passed)
    - `just test -p codex-core request_plugin_install` (17 passed)
    - `just fix -p codex-analytics`
    - `just fix -p codex-core`
    - `just fmt`
    - `git diff --check`
  • mcp: keep elicitation requests below app wire types (#29724)
    ## Why
    
    Core and tools need to request MCP elicitation without constructing
    app-server wire payloads. The request should remain a neutral protocol
    concept until app-server serializes it for a client.
    
    ## What changed
    
    - Switched core and tools to
    `codex_protocol::approvals::ElicitationRequest`.
    - Derived turn and server context inside core instead of carrying
    app-server request types through lower layers.
    - Kept the app-server payload unchanged through an explicit boundary
    conversion.
    - Removed the remaining production app-server-protocol dependency from
    tools.
    
    ## Stack
    
    This is PR 5 of 6, stacked on [PR
    #29723](https://github.com/openai/codex/pull/29723). Review only the
    delta from `codex/split-connector-metadata-types`. Next: [PR
    #29725](https://github.com/openai/codex/pull/29725).
    
    ## Validation
    
    - `codex-core` MCP coverage passed: 87 tests.
    - Tools elicitation and app-server round-trip coverage passed.
  • [apps] Thread structured icon assets through app list (#29889)
    ## Summary
    
    - Add `iconAssets` and `iconDarkAssets` to the app-list protocol.
    - Preserve structured icons through directory merging and the connector,
    app-
      server, and TUI boundaries.
    - Keep legacy logo URLs unchanged as compatibility fallbacks.
    - Update generated protocol schemas and TypeScript types.
  • [codex] Inject agent graph store into ThreadManager (#29736)
    Pick up the AgentGraphStore migration.
    
    - Inject an explicit optional agent graph store into `ThreadManager` 
    - Move all calls to spawn, close, recursive resume, and
    subtree/archive/delete/feedback traversal through it
    - Keep using  `LocalAgentGraphStore` when SQLite is available
    
    This required some changes to the interface to deal with futures:
    
    - The interface now matches `ThreadStore`'s object-safe pattern by
    returning a boxed `AgentGraphStoreFuture` directly, allowing
    `ThreadManager` to hold `Arc<dyn AgentGraphStore>`
    
    *Slight behavior change!* Unfiltered subtree enumeration now performs a
    single all-status breadth-first traversal, so a closed grandchild
    beneath an open edge is included; the previous Open-then-Closed
    traversals could not cross mixed-status paths and silently omitted it.
  • feat(app-server): list descendant threads by ancestor (#29591)
    ## Why
    
    `thread/list` can filter direct children with `parentThreadId`, but
    clients cannot request an entire spawned subtree. Discovering every
    descendant requires repeated client-side requests and gives up the
    database's existing filtering and pagination path.
    
    ## What changed
    
    Experimental clients can use `ancestorThreadId` to return strict
    descendants at any depth while `parentThreadId` retains its direct-child
    meaning. The filters are mutually exclusive, the ancestor is excluded,
    and every result preserves its immediate `parentThreadId` so callers can
    reconstruct the tree.
    
    ## How it works
    
    - **Explicit relationship:** Internal list parameters distinguish direct
    children from transitive descendants without changing the meaning of
    `parentThreadId`.
    - **Existing graph:** Persisted parent-child spawn edges remain the
    source of truth, so descendant lookup needs no schema migration or
    ancestry cache.
    - **Indexed traversal:** A recursive SQLite query starts from the
    parent-edge index, walks each generation, and applies thread filters,
    sorting, and cursor pagination in the same database request.
    - **Reconstructable results:** The response stays flat and normally
    ordered while carrying each descendant's immediate parent.
    
    ## Verification
    
    Ran 550 tests across the protocol, state, rollout, and thread-store
    crates, then reran the four focused state, store, and app-server
    descendant-listing tests after the final diff reduction. Scoped Clippy
    and formatting checks passed. Stable and experimental schema generation
    was checked; the stable fixtures remain unchanged while the experimental
    schema includes the new field.
  • Persist agent messages as response items (#29829)
    ## Why
    
    Inter-agent messages are recorded in live history as
    `ResponseItem::AgentMessage`, but rollouts stored
    `InterAgentCommunication` and rebuilt the response item during resume.
    This made the rollout differ from the actual Responses history.
    
    ## What changed
    
    - store the prepared `agent_message` response item directly
    - keep `trigger_turn` in a small local metadata record for fork
    truncation
    - keep reading older `inter_agent_communication` rollout items
  • [codex] Remove auto-compaction opt-out (#29815)
    ## Summary
    
    - remove the default-on `auto_compaction` feature flag and generated
    config schema entries
    - restore unconditional pre-turn, model-switch/hash, and mid-turn
    automatic compaction
    - expose `new_context` whenever token-budget tooling is enabled
    - remove the disabled-auto-compaction integration coverage introduced by
    #28260
    
    ## Motivation
    
    Roll back the internal auto-compaction escape hatch added in #28260.
    Automatic compaction should no longer be suppressible with `--disable
    auto_compaction`; existing manual `/compact` behavior remains unchanged.
    
    ## Testing
    
    - `just write-config-schema`
    - `just test -p codex-features` — 53 passed
    - `just test -p codex-core 'suite::compact::'` — 36 passed
    - `just test -p codex-core
    suite::token_budget::new_context_tool_starts_new_window_before_follow_up`
    — 1 passed
    - `just fix -p codex-core -p codex-features`
    - `just fmt`
    - `just test -p codex-core` — 2,778 passed, 59 failed, 16 skipped;
    failures were outside the changed compaction paths and were dominated by
    missing first-party test binaries and shell-snapshot timeouts
  • connectors: own app metadata types (#29723)
    ## Why
    
    Connector metadata is consumed by connector discovery, ChatGPT
    integration, core, and TUI code. Treating app-server's wire DTO as the
    shared domain model reverses the intended dependency direction.
    
    ## What changed
    
    - Added connector-owned app branding, review, screenshot, metadata, and
    info types.
    - Added explicit conversions in app-server and TUI while preserving
    app-server's wire payloads.
    - Removed production app-server-protocol dependencies from connectors
    and ChatGPT connector code.
    
    ## Stack
    
    This is PR 4 of 6, stacked on [PR
    #29722](https://github.com/openai/codex/pull/29722). Review only the
    delta from `codex/split-config-layer-types`. Next: [PR
    #29724](https://github.com/openai/codex/pull/29724).
    
    ## Validation
    
    - Connector and tools coverage passed.
    - App-server app-list coverage passed: 13 tests.
  • config: own layer provenance types (#29722)
    ## Why
    
    Config layer provenance describes how effective configuration was
    assembled, so it belongs with the config loader rather than in
    app-server's serialized API types.
    
    ## What changed
    
    - Moved `ConfigLayerSource`, `ConfigLayerMetadata`, and `ConfigLayer`
    ownership into `codex-config`.
    - Kept app-server's wire payloads unchanged and added explicit
    conversions at the app boundary.
    - Removed lower-level app-server-protocol dependencies from config
    consumers.
    
    ## Stack
    
    This is PR 3 of 6, stacked on [PR
    #29721](https://github.com/openai/codex/pull/29721). Review only the
    delta from `codex/split-auth-domain-types`. Next: [PR
    #29723](https://github.com/openai/codex/pull/29723).
    
    ## Validation
    
    - `codex-config` coverage passed.
    - App-server config-manager and config RPC coverage passed.
  • [plugins] Enforce marketplace source admission requirements (#29753)
    ## Why
    
    Managed marketplace source requirements only become effective when every
    local marketplace mutation path applies the same admission decision.
    This change centralizes that decision so CLI, app-server, and
    external-agent migration flows cannot add, install from, or refresh a
    disallowed source.
    
    ## What changed
    
    - Match exact normalized Git repository URLs with an optional exact
    `ref`.
    - Match Git hosts with managed regular expressions.
    - Match local marketplaces by exact absolute path.
    - Preserve the expected path/name boundary for managed OpenAI
    marketplaces.
    - Enforce source admission during marketplace add, plugin install, and
    configured Git marketplace upgrade.
    - Continue upgrading independent marketplaces when one source is
    rejected and return a per-marketplace error.
    - Load the effective requirements stack at CLI, app-server, and
    external-agent migration entry points.
    
    This PR does not filter already configured marketplaces at runtime; that
    remains in draft follow-up #29691.
    
    ## Stack
    
    This is PR 2 of 3 and is based on #29690, which introduces the
    requirements data shape and merge behavior.
    
    ## Test plan
    
    - Source matcher coverage for Git URL/ref, host-pattern, local-path, and
    managed marketplace cases.
    - Marketplace add and plugin install coverage for allowed and rejected
    sources.
    - Marketplace upgrade coverage for rejection and per-marketplace
    continuation.
  • auth: move domain mode below app wire types (#29721)
    ## Why
    
    Authentication mode is a domain concept used by login, model selection,
    telemetry, and transports. Keeping the canonical type in app-server
    protocol forces those lower-level crates to depend on an unrelated wire
    API.
    
    ## What changed
    
    - Added canonical `codex_protocol::auth::AuthMode` domain values.
    - Kept the app-server wire DTO unchanged and added an explicit app-side
    conversion.
    - Removed production app-server-protocol dependencies from login,
    model-provider-info, models-manager, and otel call paths.
    
    ## Stack
    
    This is PR 2 of 6, stacked on [PR
    #29714](https://github.com/openai/codex/pull/29714). Review only the
    delta from `codex/split-json-rpc-protocols`. Next: [PR
    #29722](https://github.com/openai/codex/pull/29722).
    
    ## Validation
    
    - Auth and login coverage passed in the focused protocol/domain test
    run.
    - App-server account and auth conversion coverage passed.
  • [codex] Assign response item IDs in forked history (#29767)
    ## Why
    
    Fork-specific response items, including the subagent usage hint, are
    appended directly to `InitialHistory::Forked`. This bypasses the normal
    history insertion path that assigns missing response item IDs when
    `Feature::ItemIds` is enabled, so the child could reconstruct and
    persist those items without IDs.
    
    ## What changed
    
    - When `Feature::ItemIds` is enabled, assign missing IDs to top-level
    `ResponseItem`s while materializing `InitialHistory::Forked`, before
    both reconstruction and persistence.
    - Preserve existing IDs and use the same owned rollout items for live
    history and persistence.
    - Extract the existing single-item ID allocation logic for reuse by the
    fork path.
    - Add coverage that verifies a fork-only developer message receives the
    same ID in live and persisted history with the feature enabled.
    
    Normal history recording, compacted-history replacement, and fork
    handling all continue to honor `Feature::ItemIds`. External-agent
    imports, normal resume, and nested legacy compaction checkpoints are
    unchanged.
    
    ## Testing
    
    - `just test -p codex-core
    record_initial_history_reconstructs_forked_transcript`
    - `just test -p codex-core
    record_initial_history_assigns_and_persists_id_for_forked_response_item`
  • [plugins] Add marketplace source requirements (#29690)
    ## Why
    
    Managed deployments need a mergeable way to declare which marketplace
    sources Codex may use. An enterprise-keyed TOML table avoids array merge
    ambiguity and lets every requirements layer use the existing config
    precedence rules without a marketplace-specific merger.
    
    ## Requirements shape
    
    ```toml
    [marketplaces]
    restrict_to_allowed_sources = true
    
    [marketplaces.allowed_sources.company_plugins]
    source = "git"
    url = "https://github.com/example/company-plugins.git"
    ref = "main"
    
    [marketplaces.allowed_sources.internal_git]
    source = "host_pattern"
    host_pattern = "^git\\.example\\.com$"
    
    [marketplaces.allowed_sources.local_plugins]
    source = "local"
    path = "/opt/company/codex-plugins"
    ```
    
    `restrict_to_allowed_sources` follows normal scalar precedence.
    `allowed_sources` follows normal recursive TOML table merge behavior:
    distinct keys accumulate and fields under the same key use normal layer
    precedence. The final `source` value later selects which fields the
    marketplace admission policy interprets.
    
    The raw rule fields remain optional while requirements layers are
    composed, so a higher-priority layer can override only `ref`, `url`, or
    another individual field. Source-specific validation and normalization
    intentionally belong to the marketplace admission layer, not
    requirements merging.
    
    This initial shape includes `git`, `host_pattern`, and `local` sources.
    It does not add npm or path-pattern rules.
    
    ## What changed
    
    - Add the marketplace requirements TOML shape to
    `ConfigRequirementsToml`, `ConfigRequirementsWithSources`, and
    `ConfigRequirements`.
    - Carry marketplace requirements through the existing regular
    requirements merge path.
    - Keep allowed-source entries as raw partial tables for downstream
    policy interpretation.
    - Cover partial same-key overlays, source changes, unknown fields, and
    unmodified local paths.
    
    This PR defines and composes the requirements only. Source admission is
    implemented by the next PR in the stack.
    
    ## Stack
    
    This is PR 1 of 3. #29753 adds source admission on top of this PR; draft
    #29691 will add runtime enforcement after it is rebased later.
    
    ## Test plan
    
    - `just test -p codex-config marketplace_`
  • [codex] Reuse compacted history replacement for new context windows (#29762)
    ## Why
    
    `start_new_context_window` independently replaced in-memory history and
    persisted a compacted checkpoint instead of using the shared
    compacted-history path. That bypassed the centralized missing-item-ID
    assignment when `item_ids` is enabled, so fresh context messages could
    enter the new context window and its persisted replacement history
    without IDs.
    
    This follows up on the token-budget compaction reset flow introduced in
    [#29743](https://github.com/openai/codex/pull/29743).
    
    ## What changed
    
    - Delegate new context-window installation to
    `replace_compacted_history`.
    - Reuse its ID assignment, in-memory replacement, world-state baseline,
    checkpoint persistence, turn-context persistence, and session-start
    bookkeeping.
    - Add focused coverage that verifies generated IDs are present in live
    history and preserved in the persisted replacement history.
    
    ## Testing
    
    - `just test -p codex-core
    start_new_context_window_assigns_and_persists_item_ids`
    - `just test -p codex-core
    new_context_tool_starts_new_window_before_follow_up`
  • Let image generation extension hosts control output persistence (#29711)
    ## Why
    
    Some extension hosts need generated images returned without writing them
    to the local filesystem or giving the model a local path.
    
    ## What changed
    
    **tl;dr**: we now conduct all extension operations in the image gen
    extension
    
    - Let hosts provide an optional image save root when installing the
    extension.
    - Save images and return path hints only when a save root is configured.
    - Return image data without saving or adding a path hint when no save
    root is configured.
    - Preserve the extension-provided `saved_path` instead of persisting
    extension images again in core.
    - Leave built-in image generation unchanged.
    
    ## Validation
    
    - `just test -p codex-image-generation-extension`
    - `just test -p codex-app-server
    standalone_image_generation_returns_saved_path_hint_to_model`
    - `just test -p codex-core
    extension_tool_uses_granted_turn_permissions_without_local_persistence`
    - `just test -p codex-core tools::handlers::extension_tools::tests`
    - tested on CODEX CLI on both save_root: CODEX_HOME and None 
    - tested on CODEX APP on both as well
  • chore: assign amsg_ IDs to agent messages (#29750)
    ## Why
    
    The `ItemIds` path fills in missing IDs before response items are
    persisted and emitted as raw item events. `ResponseItem::AgentMessage`
    is part of that same response-item stream, but it was skipped by the
    missing-ID repair path, leaving agent messages without stable item IDs
    while messages and tool items received generated IDs.
    
    Agent messages recorded through `InterAgentCommunication` also need the
    generated ID to survive rollout persistence and resume. Otherwise
    clients can observe an `amsg_` ID for the live raw response item, then
    see that same persisted agent message lose its item ID after restart.
    
    ## What changed
    
    - Assign missing `ResponseItem::AgentMessage` IDs with the `amsg_`
    prefix.
    - Persist the generated item ID on `InterAgentCommunication` and replay
    it back into the reconstructed `ResponseItem::AgentMessage` on resume.
    - Keep the persisted ID out of the model-visible inter-agent message
    envelope.
    - Keep `CompactionTrigger` and `Other` skipped because they do not get
    generated item IDs.
    - Update session/protocol tests for agent-message ID assignment and
    resume preservation.
    
    ## Manual Testing
    
    Run the local dev build using `just c --enable item_ids` to ensure this
    code is exercised:
    
    
    https://github.com/openai/codex/blob/322e33512b2d38d38d705e2ef692a8aca50decac/codex-rs/core/src/session/mod.rs#L2713-L2715
    
    In the `.jsonl` file, I saw entries like:
    
    ```json
    {
      "timestamp": "2026-06-24T00:44:03.098Z",
      "type": "inter_agent_communication",
      "payload": {
        "id": "amsg_019ef715-849a-7a50-becc-ce63c6a9c994",
    ```
    
    ## Test plan
    
    - `just test -p codex-core
    record_inter_agent_communication_preserves_item_id_in_rollout_and_resume`
    - `just test -p codex-core
    record_inter_agent_communication_sets_turn_id_in_rollout_and_resume`
    - `just test -p codex-protocol
    inter_agent_communication_response_input_item_preserves_commentary_phase`
  • core: add wait_for_environment for starting environments (#29745)
    ## Why
    
    With `DeferredExecutor`, a sampling request can begin while an
    environment is still starting. The model can see that pending state, but
    needs a way to wait for the environment within the same turn before
    continuing.
    
    Environment startup is owned by Core, so the wait tool should use the
    same request-frozen `StepContext` that advertised the starting
    environment. This keeps tool registration and execution tied to the
    exact startup operation the model saw, even if live thread state later
    changes.
    
    Supersedes #29735.
    
    ## What
    
    - register `wait_for_environment` when the current `StepContext`
    contains starting environments
    - wait on the selected `StartingTurnEnvironment` shared resolution and
    return a bounded ready or failed result
    - rebuild the next request normally, removing the wait tool and exposing
    ready environment tools, or reporting the environment as unavailable
    after failure
    
    ## Testing
    
    - `just test -p codex-core deferred_executor_`
    - verifies the wait tool is replaced by environment-backed tools after
    startup
    - verifies startup failure removes both the wait tool and unavailable
    environment tools while notifying the model
  • Support thread-level originator overrides (#29477)
    ## Why
    
    Work(TPP) threads can be launched from the Desktop app, but if they all
    keep the Desktop app's default originator then downstream attribution
    cannot distinguish local Work launches from cloud-backed Work launches.
    `thread/start.serviceName` already carries that launch signal, while
    `SessionMeta.originator` is the durable thread-level value that survives
    resume and fork.
    
    This change converts the Desktop Work service names into an effective
    originator at thread creation time, persists that originator with the
    thread, and keeps using it for later model requests and memory writes.
    
    ## What changed
    
    - Map `CODEX_WORK_LOCAL` and `CODEX_WORK_CLOUD` service names to
    per-thread originators, while preserving
    `CODEX_INTERNAL_ORIGINATOR_OVERRIDE` as the highest-precedence override.
    - Persist the effective originator in `SessionMeta.originator`, read it
    back on resume/fork, and inherit the parent originator for subagent
    spawns when there is no persisted session metadata.
    - Handle truncated `SpawnAgentForkMode::LastNTurns` forks by falling
    back to the live parent originator when the forked history no longer
    includes `SessionMeta`.
    - Thread the per-thread originator through Responses headers,
    websocket/compaction request paths, thread-store creation, rollout
    metadata, and memory stage-one telemetry.
    
    ## Verification
    
    - `just test -p codex-core
    agent::control::tests::spawn_thread_subagent_inherits_parent_originator_without_fork
    agent::control::tests::spawn_thread_subagent_fork_last_n_turns_inherits_parent_originator_without_session_meta
    thread_manager::tests::originator_override_precedes_service_name_remapping`
    - `just test -p codex-core
    agent::control::tests::resume_thread_subagent_restores_stored_metadata_and_effective_multi_agent_mode`
    - `just test -p codex-memories-write`
    - `just fix -p codex-core -p codex-memories-write`
    - `git diff --check`
  • core: reset context for token budget compaction (#29743)
    ## Why
    
    When `Feature::TokenBudget` is enabled, compaction should behave like
    `new_context`: start a fresh context window with the standard injected
    context, without asking the server to summarize old history and without
    carrying prior user or assistant messages into the next model request.
    
    This is still a compaction operation from the client lifecycle
    perspective. Manual `/compact` and auto-compaction should keep the same
    observable side effects that clients and hooks expect, including compact
    hooks and `TurnItem::ContextCompaction`.
    
    ## What changed
    
    - Added `compact_token_budget` to run token-budget manual and inline
    auto-compaction through a shared compaction lifecycle.
    - Split pending `new_context` requests from forced context-window
    startup: `take_new_context_window_request()` consumes pending requests,
    and `start_new_context_window()` installs a fresh context window.
    - Routed token-budget manual `/compact` and inline auto-compaction to
    install a fresh context window locally instead of calling server/local
    summarization.
    - Preserved compact lifecycle side effects for token-budget compaction
    by running pre/post compact hooks and emitting `ContextCompaction` item
    start/completion events.
    - Updated token-budget tests to assert fresh window IDs, absence of
    server-side compaction calls, dropped prior transcript messages/tool
    output after reset, and compact hook/item lifecycle behavior.
    
    ## Testing
    
    - `just test -p codex-core
    token_budget_context_uses_new_window_after_compaction`
    - `just test -p codex-core token_budget_compaction_runs_compact_hooks`
    - `just test -p codex-core
    token_budget_mid_turn_auto_compaction_resets_before_active_follow_up`
    
    ---------
    
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • [codex] rename rollout budget error to session budget error (#29744)
    ## Summary
    
    - rename the rollout-budget exhaustion error from
    `RolloutBudgetExceeded` to `SessionBudgetExceeded`
    - expose the matching app-server v2 wire value as
    `sessionBudgetExceeded`
    - regenerate JSON/TypeScript schema fixtures and update the app-server
    docs and focused tests
    
    This is a naming-only follow-up to #29715 based on [Pavel's review
    suggestion](https://github.com/openai/codex/pull/29715#discussion_r3463183480).
    Runtime behavior is unchanged.
    
    ## Tests
    
    - `just test -p codex-core rollout_budget`
    - `just test -p codex-app-server-protocol`
    - `just fmt`
    - `just write-app-server-schema`
  • fix: scope context remaining to body window (#29665)
    ## Why
    
    With `model_auto_compact_token_limit_scope = "body_after_prefix"`, the
    persistent prefix should not count against the active body window.
    `get_context_remaining` and the token-budget reminder should report the
    same usable body-after-prefix window that auto-compaction uses, rather
    than the total token count since the session began.
    
    This is stacked on #29664 so the mechanical move from `turn.rs` is
    isolated from the behavior fix.
    
    ## What
    
    - Extends `ContextWindowTokenStatus` with `context_remaining_tokens`.
    - Updates `get_context_remaining` to use the shared context-window
    accounting.
    - Adds integration coverage for body-after-prefix reminder timing and
    `get_context_remaining` output.
    
    ## Testing
    
    - `just test -p codex-core body_after_prefix_window`
    - `just test -p codex-core auto_compact_body_after_prefix`
    - `just fix -p codex-core`
  • refactor: extract context window token status (#29664)
    ## Why
    
    This PR keeps the mechanical helper extraction separate from the
    behavior change in #29665. The follow-up needs the token-window
    accounting from `turn.rs` in another call path, but reviewing that is
    much easier when the helper extraction is separate from the semantic
    change.
    
    ## What
    
    - Adds `session/context_window.rs` with `ContextWindowTokenStatus`.
    - Moves the existing auto-compaction token-status calculation out of
    `session/turn.rs`.
    - Replaces the duplicated inline remaining-token calculation in
    `turn.rs` with `tokens_until_compaction()`.
    
    This PR is intended to be behavior-preserving. The
    `get_context_remaining` behavior change is stacked separately in #29665.
    
    ## Testing
    
    - `just test -p codex-core auto_compact_body_after_prefix`
    
    
    
    
    
    
    
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/29664).
    * #29665
    * __->__ #29664
  • [codex] surface rollout budget exhaustion (#29715)
    ## Summary
    - surface shared rollout-budget exhaustion as
    `CodexErr::RolloutBudgetExceeded` instead of a generic interrupted turn
    - map it through the existing `CodexErrorInfo` and app-server v2
    `codexErrorInfo` path
    - keep local compaction from retrying after the shared rollout budget is
    exhausted
    
    This gives app-server clients a stable `rolloutBudgetExceeded` error
    they can classify without guessing from `status="interrupted"`.
    
    ## Tests
    - `just test -p codex-core rollout_budget`
  • Make selected plugin roots URI-native (#28918)
    ## Why
    
    Selected capability roots belong to the executor filesystem, not the
    app-server host. Converting their path strings into the host's native
    `Path` breaks whenever the two machines use different path conventions,
    such as a Windows executor behind a Unix app-server.
    
    This PR establishes `PathUri` as the selected-plugin boundary so the
    executor remains authoritative for its paths.
    
    ## What changed
    
    - Require `selectedCapabilityRoots[].location.path` to be a canonical
    `file:` URI and deserialize it directly as `PathUri`; native path
    strings are rejected.
    - Update the app-server schema, generated TypeScript, examples, and
    request coverage for the URI contract.
    - Keep selected roots, resolved plugin locations, manifest paths, and
    manifest resources as `PathUri`.
    - Inspect and read plugin roots and manifests only through the selected
    environment's `ExecutorFileSystem`.
    - Parse executor manifests with the shared URI-native parser from #29620
    instead of projecting them onto the host filesystem.
    - Enforce resource containment lexically and preserve the root URI's
    POSIX or Windows path convention.
    - Cover foreign Windows plugin roots and URI-native manifest resources.
    
    ```text
    thread/start
      selectedCapabilityRoots[].location.path = "file:///C:/plugins/demo"
                                  | PathUri
                                  v
                        ExecutorFileSystem
                                  |
                                  +--> plugin.json
                                  +--> manifest resources
    ```
    
    This PR stops at the shared selected-plugin representation. The next two
    PRs remove the remaining host-path projections in the skill and MCP
    consumers.
    
    ## Stack
    
    1. #29614 — add lexical `PathUri` containment.
    2. #29620 — share URI-native manifest path resolution.
    3. **This PR** — keep selected plugin roots and resources URI-native.
    4. #29626 — load executor skills without host path conversion.
    5. #29628 — resolve executor MCP working directories without host path
    conversion.
  • core: persist initial context window metadata (#29519)
    ## Why
    
    PR #29494 made context-window IDs visible to the model by wrapping the
    token-budget window payload in `<context_window>`, but rollout JSONL
    consumers still could not see the initial window identity by tailing the
    session file. Compacted rollout items carry window IDs only after
    compaction has happened, so a session with no compaction had no durable
    JSONL record for window 0.
    
    This change gives tailing consumers a stable initial-window record at
    session creation time.
    
    ## What Changed
    
    - Added `session_meta.context_window.window_id` for the initial
    context-window identity.
    - `CreateThreadParams` now requires `initial_window_id: String`, so
    thread-store callers cannot accidentally create new threads without
    window-0 metadata.
    - Live thread creation derives the persisted initial window ID from the
    same `AutoCompactWindowIds` used to initialize `SessionState`, keeping
    runtime state and JSONL metadata aligned.
    - Rollout reconstruction uses `session_meta.context_window.window_id` as
    the initial-window fallback and derives `window_number = 0`,
    `first_window_id = window_id`, and `previous_window_id = None`
    internally.
    - Fork reconstruction intentionally uses the same rollout reconstruction
    path; consumers that need to distinguish copied initial-window metadata
    can use the rollout `thread_id`.
    - Legacy compactions without `window_number` still use compaction-count
    fallback accounting instead of being reset to window 0 by the
    initial-window fallback.
    - Compacted rollout metadata still takes precedence once compaction
    records exist, preserving the richer chain fields there.
    
    ## JSONL Shape
    
    Real rollout JSONL is one object per line. This example is expanded for
    readability, but shows the new initial `session_meta.context_window`
    record followed by the existing compacted rollout item shape that also
    carries window IDs:
    
    ```jsonl
    {
      "timestamp": "2026-06-22T12:00:00.000Z",
      "type": "session_meta",
      "payload": {
        "session_id": "<THREAD_ID>",
        "id": "<THREAD_ID>",
        "timestamp": "2026-06-22T12:00:00.000Z",
        "cwd": "/repo",
        "originator": "codex",
        "cli_version": "0.0.0",
        "source": "cli",
        "model_provider": "<MODEL_PROVIDER>",
        "context_window": {
          "window_id": "<INITIAL_WINDOW_ID>"
        }
      }
    }
    ...
    {
      "timestamp": "2026-06-22T12:34:56.000Z",
      "type": "compacted",
      "payload": {
        "message": "<COMPACTION_SUMMARY>",
        "replacement_history": [
          "..."
        ],
        "window_number": 1,
        "first_window_id": "<INITIAL_WINDOW_ID>",
        "previous_window_id": "<INITIAL_WINDOW_ID>",
        "window_id": "<NEXT_WINDOW_ID>"
      }
    }
    ```
    
    The nested `context_window` object is intentional: it gives rollout
    consumers a stable namespace for context-window metadata while only
    writing the non-derivable initial `window_id`. For the initial window,
    `window_number`, `first_window_id`, and `previous_window_id` are derived
    internally instead of being written to the rollout.
    
    ## Verification
    
    - `just test -p codex-protocol`
    - `just test -p codex-rollout
    recorder_materializes_on_flush_with_pending_items`
    - `just test -p codex-core reconstruct_history`
    - `just test -p codex-core
    record_initial_history_reconstructs_forked_transcript`
    - `just test -p codex-thread-store`
    - `just test -p codex-state`
    - `just test -p codex-app-server
    thread_read_returns_summary_without_turns`
    - `just test -p codex-rollout persistence_metrics`
  • test: branch on target OS instead of runner flavor (#29712)
    ## Why
    
    Core tests should branch on the executor's operating system, not on
    runner details such as Docker or Wine. This keeps platform behavior
    stable as new test backends are added and reserves Wine-specific skips
    for actual runner debt.
    
    ## What
    
    - Add `TestTargetOs` and target/host-aware skip helpers while keeping
    `TestEnvironment` internal.
    - Replace topology enum access with remote predicates and a narrow
    Docker accessor.
    - Migrate OS-semantic Wine skips, preserve runner-specific gaps, and
    document the skip taxonomy.
    
    ## Validation
    
    - `just test -p core_test_support`
    - `just test -p codex-core
    remote_test_env_can_connect_and_use_filesystem`
    - `bazel test //codex-rs/core:core-all-wine-exec-test
    --test_output=errors` reached test execution; unrelated existing
    view-image, path, and timing failures remain.
    - `just test -p codex-core` and `just test` reached broad test
    execution; this checkout has unrelated helper, sandbox, and timing
    failures.
  • code-mode: Rename codex_code_mode::CodeModeService (#29716)
    Mechanical rename of CodeModeService => InProcessCodeModeSession
    
    This already implements a CodeModeSession as its prime interface to
    Core. The name was vestigial _and_ confusing af when embedded inside
    core::tools::code_mode::CodeModeService
  • feat(guardian): include connected account email in app reviews (#27045)
    ## Why
    
    auto review reviews Codex App tool calls using connector metadata such
    as the app ID, name, and description. That metadata does not identify
    the account behind the OAuth connection.
    
    For Google Drive, this means auto review cannot distinguish a Drive
    connection authenticated as `user@email.com` from a personal Drive
    account. Uploading work data can therefore look like a transfer to a
    personal destination even though the connector service already knows the
    authenticated account email.
    
    ## What changed
    
    - Read `_meta._codex_apps.connected_account_email` while resolving
    approval metadata for built-in Codex App tools.
    - Include the connected account email in the structured MCP tool action
    sent to auto review.
    - Trim empty values and omit the field when the connector link has no
    account email.
    - Update existing auto review request constructors and add coverage for
    request construction and JSON serialization.
    
    ## Security
    
    Only metadata from the trusted built-in `codex_apps` MCP server is
    accepted. Custom MCP servers cannot inject a connected account email
    into auto review reviews; the new regression test verifies that spoofed
    metadata is ignored.
    
    The email is used only in auto review's private review request. This
    change does not add it to model-visible tool descriptions, app-server
    approval events, or auto review assessment/review analytics.
  • Add MCP tool call error metrics (#28976)
    [Codex Thread
    019edc37-5345-7272-92c9-bf5494cf3819](https://codex-thread-link.openai.chatgpt-team.site/thread/019edc37-5345-7272-92c9-bf5494cf3819)
    
    ## Summary
    
    - count MCP `CallToolResult.isError` responses as failed calls instead
    of successful transport-level calls
    - add `codex.mcp.call.error` with bounded `error_type` and trusted
    plugin-service `error_code` dimensions
    - record the same error classification on MCP tool-call spans while
    keeping untrusted server error text out of metric labels
    
    ## Scope
    
    - no changes to MCP routing, retries, tool behavior, configuration, or
    public APIs
    - request failures remain grouped as `mcp_request`; separating
    connection, timeout, protocol, and JSON-RPC failures requires preserving
    typed errors through the existing flattened error boundary
    
    ## Testing
    
    - `just test -p codex-core 'mcp_tool_call::tests::'` (75 passed)
    - `just fix -p codex-core`
    - `just fmt`
    - `just test -p codex-core` (2,676 passed; 80 unrelated environment
    failures from missing test binaries, sandbox signals, and read-only
    paths)
  • core: use current step environments for tools (#29547)
    ## Why
    
    With deferred executors, an environment can become ready between two
    sampling requests in the same turn. The model-visible environment
    update, advertised tools, and eventual tool execution must all describe
    the same request-time view.
    
    Otherwise, a request built while only environment B is ready can
    advertise a tool without an `environment_id`; if higher-priority
    environment A becomes ready before execution, that call could silently
    run in A instead.
    
    This PR is stacked on #29527.
    
    ## Design
    
    `run_turn` captures one `Arc<StepContext>` at each sampling-request
    boundary. That step owns the request's `TurnContext` and environment
    snapshot.
    
    - World-state environment updates and tool planning borrow that same
    step.
    - `ToolCallRuntime` retains the `Arc` while asynchronous tool calls
    execute.
    - `ToolInvocation` carries the step to handlers; its temporary `turn`
    compatibility field is derived from the same object.
    - `ToolRouter` does not retain `StepContext`; it only uses it while
    constructing the request's tool set.
    - With `DeferredExecutor` disabled, step capture keeps using the
    environments frozen at turn start.
    
    Simply: every sampling request gets one consistent picture of its
    environments, from what the model sees through where its tool calls run.
    
    ## What changed
    
    - Build environment-dependent tool specs from the current request's
    `StepContext`.
    - Use that same step for unified exec, legacy shell, `apply_patch`,
    `view_image`, and `request_permissions` execution.
    - Hide environment-backed tools, including `request_permissions`, while
    no environment is attached.
    - Resolve legacy shell paths and metadata from the selected step
    environment instead of the stale turn-start environment.
    - Capture explicit steps at non-turn-loop boundaries such as compaction,
    prompt debug, and startup prewarm.
    - Reconcile prompt-debug history from the same step used to build its
    tools.
    
    ## Follow-up
    
    - Bind yielded code-mode cells to the tool runtime that created them, so
    nested calls made after yielding continue to use the originating
    request's `StepContext`.
    
    ## Test plan
    
    - `just test -p codex-core
    deferred_executor_updates_context_and_tools_after_startup`
    - `just test -p codex-core
    environment_count_controls_environment_backed_tools`
    - `just test -p codex-core
    build_prompt_input_includes_context_and_user_message`
  • core: resolve view_image paths in selected environment (#29526)
    ## Why
    
    view_image needs to support foreign OS remote executors.
    
    ## What
    
    - resolve image paths against the selected environment as `PathUri` and
    read them through that environment's filesystem
    - keep app-server's public path field wire-compatible as
    `LegacyAppPathString`, with purpose-specific UI rendering
    - cover relative and absolute target-native paths in the core
    integration test and run the full `view_image` suite under wine-exec
    without skips
  • [codex] allow image generation with provider auth (#29513)
    ## Summary
    
    - allow the native Responses API `image_generation` tool when the active
    provider carries CCA's non-empty `x-openai-actor-authorization` header
    - preserve the Codex-managed ChatGPT auth path, scoped to providers that
    actually require OpenAI auth
    - keep generic custom providers excluded, including when unrelated
    ChatGPT credentials are cached
    - retain the existing feature, provider-capability, and
    image-input-modality gates
    
    ## Why
    
    CCA authenticates its inference requests through the active provider's
    `x-openai-actor-authorization` and `ChatGPT-Account-ID` headers, so it
    does not have a Codex-managed login session. The previous gate therefore
    hid the native hosted image-generation tool despite an authenticated
    codex-backend path.
    
    This change is intentionally limited to the native hosted tool. It adds
    no extension, MCP, plugin-service, session-source, token plumbing, or
    new provider configuration surface.
    
    ## Tests
    
    - `cargo test -p codex-core
    hosted_tools_follow_provider_auth_model_and_config_gates`
    - `cargo fmt --all -- --check`
    - `git diff --check origin/main`
  • chore(core) rm AskForApproval::OnFailure (#28418)
    ## Summary
    Deletes the OnFailure variant of the `AskForApproval` enum. This option
    has been deprecated since #11631.
    
    ## Testing
    - [x] Tests pass
  • Prepare managed network sandbox context (#29456)
    ## Why
    
    Managed network configures commands to use local HTTP and SOCKS proxies.
    For commands delegated to the exec server, the proxy environment and the
    sandbox policy were prepared separately. On macOS, that meant a command
    could receive `HTTPS_PROXY=http://127.0.0.1:43123` while Seatbelt still
    denied access to port `43123`.
    
    ## What changed
    
    `NetworkProxy` now prepares the command environment and sandbox context
    together from the same runtime snapshot:
    
    ```text
    Prepared managed network
    ├── command environment: HTTPS_PROXY=http://127.0.0.1:43123
    └── sandbox context: allow outbound to 127.0.0.1:43123
    ```
    
    That context travels with remote exec requests. The exec server
    preserves the managed proxy and CA environment, and macOS Seatbelt
    allows only the prepared loopback proxy ports without enabling broad
    network access or local binding.
    
    The protocol field is optional and the existing enforcement flag remains
    in place, preserving compatibility with callers that do not send the new
    context.
  • app-server: document thread and turn IDs are UUID7 (#27714)
    It's actually a very nice property that these are UUID7s, so documenting
    them so we think twice before changing it away from UUID7s in the
    future.
  • core: use turn-owned world state for inline compaction (#29527)
    ## Why
    
    Follow-up to #29249 and its [compaction review
    thread](https://github.com/openai/codex/pull/29249#discussion_r3455055101).
    
    During a turn, environment readiness can change between sampling
    requests. Inline compaction must render the same model-visible
    `WorldState` used by the request it follows. Rebuilding that state
    during compaction can observe a newer environment, make replacement
    history disagree with what the model saw, and suppress the next
    environment update.
    
    ## What changed
    
    - Make `run_turn` own the current `Arc<WorldState>` and replace it only
    between sampling requests.
    - Build each state from an explicitly chosen environment snapshot, diff
    deferred-executor steps against the turn-owned state, and retain the
    latest state in `ContextManager` only for cross-turn and resume
    tracking.
    - Pass the exact turn-owned state into inline compaction and explicit
    new-context-window replacement.
    - Carry that state with
    `InitialContextInjection::BeforeLastUserMessage`, so replacement context
    and its stored baseline cannot come from different snapshots.
    - Remove obsolete state-recapture helpers and ambiguous TurnContext-only
    WorldState builders.
    - Add an integration test that moves an environment from starting to
    ready during a paused turn, triggers compaction, and verifies the next
    request receives the readiness update exactly once.
    
    ## Test plan
    
    - `just test -p codex-core
    deferred_executor_compaction_preserves_then_updates_environment_once`
    - `just test -p codex-core process_compacted_history`
    - `just test -p codex-core mid_turn_continuation_compaction`
    - `just test -p codex-core build_initial_context`
    - `just test -p codex-core
    ignores_session_prefix_messages_when_truncating`
  • Shut down superseded MCP managers on refresh (#29608)
    ## Summary
    
    MCP refresh replaced the published connection manager without shutting
    down the manager it superseded. If another task retained that old
    manager, its stdio MCP processes stayed alive and accumulated across
    refreshes.
    
    Atomically swap in the refreshed manager, then explicitly shut down the
    exact manager returned by the swap. Add a process-level regression test
    that retains the old manager during refresh and verifies its stdio
    process exits while the replacement remains available.
    
    ## Context
    
    Explicit cleanup was lost when manager publication moved to `ArcSwap`.
    Dropping the old manager is not a reliable shutdown boundary because
    active callers can retain its `Arc` and underlying client process
    handles.
  • [core] debounce current-time reminders by elapsed time (#29659)
    ## Summary
    - rename `reminder_interval_model_requests` to
    `reminder_interval_seconds`
    - read the configured time provider before every model request and
    inject a reminder only after the configured number of seconds has
    elapsed
    - preserve immediate first delivery and forced delivery after compaction
    changes the context window
    
    ## Tests
    - `just test -p codex-core current_time_reminder`
  • Share resumed rollout history (#28426)
    ## Summary
    
    Resuming a persisted thread currently deep-clones its complete rollout
    history several times. `InitialHistory` is retained for the app-server
    response, copied into thread persistence, and copied again by read-only
    accessors. These copies scale with the complete rollout rather than the
    bounded model context and add measurable latency for large sessions.
    
    This change stores resumed rollout history in `Arc<Vec<RolloutItem>>`.
    Rollout loading wraps the parsed vector once, while app-server response
    construction, session initialization, and thread persistence share it
    through inexpensive `Arc` clones. Read-only history access now returns a
    borrowed slice, and fork paths use `Arc::unwrap_or_clone` where they
    genuinely need mutable ownership. Rollout reconstruction also consumes
    its temporary context instead of cloning the reconstructed model
    history.
    
    The serialized representation remains unchanged. In an artificial 123 MB
    rollout benchmark, sharing resumed history reduced cold resume latency
    by roughly 9–10%. The affected crates compile with their test targets,
    all 80 thread-store tests pass, and the Bazel dependency lock remains
    valid.
  • Namespace multi-agent v2 tools under collaboration (#29067)
    ## Summary
    
    Multi-agent v2 tools now use the fixed `collaboration` namespace when
    namespace tools are available. This keeps the model-visible hint and the
    actual tool surface aligned around `functions.collaboration.*`, without
    exposing an unshipped namespace knob to users.
    
    The PR also removes the old `features.multi_agent_v2.tool_namespace`
    config/schema surface, updates the MAv2 test fixtures for namespaced
    calls, and fixes stale `TurnContext.features` references that were
    breaking `codex-core` builds.
    
    ## Changes
    
    - Expose MAv2 tools under `collaboration` instead of relying on a
    configurable namespace.
    - Remove `tool_namespace` from MAv2 TOML config, resolved config,
    validation, schema, and tests.
    - Update tool-planning and integration fixtures to assert or emit
    namespaced MAv2 tool calls.
    - Read feature state through `TurnContext.config.features` in the
    multi-agent mode context paths.
    
    ## Testing
    
    - `just write-config-schema`
    - `just test -p codex-features`
  • Fix Codex Apps auth elicitation hang (#29615)
    ## Summary
    - Require the reserved Codex Apps MCP server name to be present in the
    connection manager before treating it as host-owned.
    - Update auth elicitation tests to model an installed host-owned Codex
    Apps server without sending startup events to the test session.
    
    ## Why
    PR #29518 replaced the old host-owned flag with a name-only check. That
    made non-host-owned tests with the reserved codex_apps name enter auth
    elicitation and wait forever for a response.
  • Allow codex sandbox to consume MCP sandbox state (#29358)
    ## Summary
    
    - let `codex sandbox` accept the JSON value from
    `codex/sandbox-state-meta`
    - require the payload `permissionProfile` instead of falling back to
    ambient permissions
    - reuse the existing macOS, Linux, and Windows launch paths, treating
    external sandbox state conservatively as read-only
    - let opaque forwarders add runtime read roots and disable direct
    network access without decoding the payload
    
    Builds on #29113, which is now on `main`.
    
    ## Tests
    
    - `just test -p codex-cli debug_sandbox::tests`
    - `cargo build -p codex-rmcp-client --bin test_stdio_server`
    - `just test -p codex-core
    stdio_mcp_tool_call_includes_sandbox_state_meta`
    - `just test -p codex-mcp`
    - `just fmt`
  • Centralize Codex Apps client handling (#29528)
    ## Why
    
    Codex Apps-specific behavior is currently distributed across cache
    helpers, startup, tool conversion, and model-visible annotation. Each
    layer independently checks the reserved server name, which obscures the
    boundary between trusted host-owned connector metadata and regular MCP
    server data.
    
    Classifying the server once when `AsyncManagedClient` is created gives
    the client a single source of truth and makes the two processing paths
    explicit.
    
    ## What changed
    
    - Record whether an `AsyncManagedClient` represents the Codex Apps
    server at construction time.
    - Route startup cache loading, cache persistence, and cache telemetry
    through the Codex Apps branch.
    - Split uncached tool conversion between Codex Apps normalization and
    regular MCP metadata sanitization.
    - Split model-visible schema and plugin provenance handling along the
    same boundary.
    - Remove redundant server-name guards from helpers that are now called
    only from the Codex Apps branch.
    
    ## Verification
    
    - Preserve behavioral coverage that verifies Codex Apps connector
    metadata and the complete converted `ToolInfo` shape.
    
    ## Stack
    
    Depends on #29518.
  • [codex] Use input items for Responses Lite tools (#27946)
    When using Responses Lite, we should all use `additional_tools` and a
    developer item instead of the top level tools array & instructions
    field. This keeps things 1-to-1.
    
    Forced namespacing for _all_ tools will land in a following PR after
    some coordination & fixes in Responses API (around collisions & return
    items).
    
    The goal is to eventually expand the scope of this to _all_ requests
    from codex, but that will require larger coordination across providers &
    slower rollout.
  • Remove redundant Codex Apps manager flag (#29518)
    ## Why
    
    Codex Apps server admission is already decided before
    `McpConnectionManager` is constructed. `effective_mcp_servers` and
    `effective_mcp_servers_from_configured` remove the server when the apps
    feature or required authentication is unavailable, so storing the same
    decision on the manager duplicates state that can drift from the
    effective server map.
    
    ## What changed
    
    - Remove `host_owned_codex_apps_enabled` from `McpConnectionManager` and
    its constructor.
    - Identify the host-owned Codex Apps server by its reserved server name
    once it is present in the effective server map.
    - Remove the now-unused flag calculations and constructor arguments from
    production and test callsites.