Commit Graph

7359 Commits

  • [codex] remove EnvironmentPathRef (#27433)
    We're switching to using a static encoding of the host path in
    `PathUri`. We may need a type like this again but we can add it when
    it's more compelling.
    
    Stacked on #27454.
  • [codex] Provide ARM64 MinGW powl compatibility support (#27323)
    ## Why
    
    Windows ARM64 uses 64-bit `long double`, but the LLVM MinGW Bazel
    configuration omits the upstream `powl` compatibility source and does
    not link the `mingwex` archive that owns it. Cross-linking the release
    binary therefore fails with an unresolved `powl` symbol.
    
    ## What changed
    
    Patch the LLVM module to compile `math/arm-common/powl.c` into the ARM64
    MinGW extension sources and add `-lmingwex` to the Windows toolchain
    defaults.
    
    ## Validation
    
    - `just bazel-lock-check`
    
    Stack: 3 of 6. Depends on #27322.
  • feat: disable orchestrator skills for now (#27646)
    Temp disable orchestrator-only skills while waiting for the endpoint to
    be fixed
  • [codex] revert concurrent npm publishing (#27639)
    In https://github.com/openai/codex/actions/runs/27354608310, the
    concurrency introduced by
    
    https://github.com/openai/codex/commit/5e50e7e639c9284ceac24a5498b73a5602fb6615
    caused the npm publish job to fail.
    
    The six platform tarballs contain different versions of the same
    `@openai/codex` package. Every publish updates the same packument, so
    only two concurrent updates succeeded while four failed with HTTP 409.
    
    Serializing that group would leave only the responses API proxy running
    in parallel. Saving one publish does not justify the nested `xargs`
    machinery needed to express those groups.
    
    Restore the serial publish loop and document why the platform variants
    must not publish concurrently. Platform packages remain ahead of the
    root CLI wrapper, and the SDK remains after its exact root dependency.
  • [codex] Surface runtime warnings in codex exec (#27415)
    ## Why
    
    `codex exec` drops thread-scoped warning notifications. Warnings
    discovered while a thread starts, including unreadable or invalid UTF-8
    project `AGENTS.md` files, therefore become silent.
    
    ## What changed
    
    - Process global and primary-thread warning notifications while
    continuing to ignore warnings from unrelated threads.
    - Render runtime warnings in human output and expose them through the
    existing non-fatal error item in JSONL output.
    - Add focused routing, rendering, and malformed project-instruction
    coverage.
  • [codex] add cross-platform filesystem adapter coverage (#27454)
    ## Why
    
    The exec-server's existing filesystem tests only run on `#[cfg(unix)]`.
    We should be running the applicable ones on Windows, and also include
    the basic filesystem operations that will be modified by migrating to
    `PathUri`.
    
    ## What
    
    Split platform-neutral local/remote tests into a shared Unix/Windows
    suite while keeping the existing `AbsolutePathBuf` API, and add Windows
    junction canonicalization coverage.
  • [codex] Propagate plugin app categories (#27420)
    ## What
    - Parse optional `.app.json` `category` overrides for plugin apps.
    - Add nullable `category` to `AppSummary` and `AppTemplateSummary` in
    the app-server protocol.
    - Fall back from `branding.category` to the first non-empty
    `app_metadata.categories` value when building app/template summaries.
    - Regenerate schema/type fixtures and update plugin read/install tests.
    
    ## Why
    The plugin details UI needs a normalized per-app category. Some apps
    only provide their default category in metadata, while others need a
    local `.app.json` override.
  • lint: allow self-documenting builder arguments (#27507)
    Builder-style setters often repeat the setting name in both the method
    and its sole argument. Calls such as `.enabled(false)` are already
    self-documenting, so requiring `/*enabled*/` adds noise without
    clarifying the call.
    
    ## What changed
    
    - Exempt a method's sole non-self argument when its resolved parameter
    name matches the method name.
    - Continue validating any explicit argument comment against the resolved
    parameter name.
    - Continue requiring comments when method and parameter names differ or
    when a method has multiple non-self arguments.
    - Document the exception in `AGENTS.md` and the lint's own behavior
    documentation.
    
    ## Examples
    
    Before this change we'd need redundant comments like this:
    
    ```rust
    builder.enabled(/*false*/ false);
    builder.retry_count(/*retry_count*/ 3);
    builder.base_url(/*base_url*/ None);
    ```
    
    Now can be written like this:
    
    ```rust
    builder.enabled(false);
    builder.retry_count(3);
    builder.base_url(None);
    ```
    
    Still disallowed:
    
    ```rust
    client.set_flag(true); // Method name does not match parameter `enabled`.
    options.enabled(false, /*retry_count*/ 3); // More than one non-self argument.
    options.enabled(/*value*/ false); // Explicit comment does not match `enabled`.
    ```
    
    ## Validation
    
    Added UI coverage for boolean, numeric, and `None` builder arguments,
    multi-argument methods, and explicit comment mismatches. Ran `rustup run
    nightly-2025-09-18 cargo test` in `tools/argument-comment-lint`.
  • Print TUI session info on fatal exits (#27417)
    ## Summary
    
    TUI exits printed the resume/session summary only after checking the
    exit reason. On fatal exits, both CLI wrappers wrote the error and
    called `process::exit(1)` immediately, so an active session that ended
    on a fatal error could skip the session information entirely.
    
    This change prints the normal exit summary before returning the fatal
    nonzero exit code. If a fatal exit has a known thread id but no
    resumable rollout hint, it prints `Session ID: <id>` instead of staying
    silent. It also flushes stdout before `process::exit(1)` so the summary
    line is not lost during process teardown.
    
    ## Implementation
    
    - Apply the fatal-exit ordering fix in both `codex` and standalone
    `codex-tui`.
    - Keep normal user-requested exit behavior unchanged.
    - Preserve the existing resume hint when a rollout is resumable, and use
    the raw thread id only as a fatal-exit fallback.
  • Emit plugin ID on MCP tool call analytics events (#27483)
    MCP tool-call items already carry the runtime-resolved plugin owner, but
    the analytics reducer dropped that field. Forwarding the existing value
    provides direct attribution without downstream server-name inference.
    
    ## Summary
    
    - emit `plugin_id` on `codex_mcp_tool_call_event` payloads
    - preserve `null` for MCP calls without a plugin owner
    - verify the serialized field through the MCP item lifecycle test
    
    ## Test
    
    - `cd codex-rs && just test -p codex-analytics`
    - `cd codex-rs && just fix -p codex-analytics`
    - `cd codex-rs && just fmt`
  • Remove TUI legacy Windows sandbox dependency (#27490)
    ## Why
    
    This is part of an ongoing attempt to eliminate the TUI's direct
    dependency on core features. When we moved the TUI to the app server, we
    left a `legacy_core` shim that re-exported some remaining core symbols
    for the TUI. The intent was to eventually remove all of these.
    
    In this PR, we remove the symbols related to the Windows sandbox.
    
    The change should be behavior-neutral and low risk because it's just
    refactoring and removal of code that is now effectively dead.
    
    When working on this PR, I noticed a big existing problem that affects
    mixed-platform remoting. For example, if you run the TUI on a Linux box
    and remote into a Windows box, the TUI logic doesn't properly handle
    Windows sandbox setup properly. Fixing this is beyond the scope of this
    PR, but I've left a TODO comment in place so we don't forget.
    
    ## What changed
    
    - Move the remaining TUI-specific sandbox level, setup, telemetry, and
    read-root helpers into `codex-tui`, calling `codex-windows-sandbox`
    directly.
    - Remove the Windows sandbox namespace and read-root grant re-exports
    from the client-side `legacy_core` facade.
    - Remove the dormant pre-elevation prompt fallback guarded by the
    permanently enabled `ELEVATED_SANDBOX_NUX_ENABLED` switch. The reachable
    elevated and non-elevated setup flows remain unchanged.
  • [codex] download only release artifacts (#27529)
    In https://github.com/openai/codex/actions/runs/27308011621, the
    release job downloaded 10.0 GiB of workflow artifacts in 87 seconds,
    then discarded 42 artifacts accounting for 3.3 GiB.
    
    Select target and supplemental release artifact patterns at download
    time. This also excludes duplicate Cargo timing files without a cleanup
    pass and should reduce total release time by about 30 seconds.
  • [codex] publish DotSlash alongside npm (#27528)
    In https://github.com/openai/codex/actions/runs/27308011621,
    preparing and publishing the three DotSlash configurations took 72
    seconds after creating the GitHub release. npm publication could not
    start until those independent steps finished.
    
    Move DotSlash publication to a sibling job that starts after the GitHub
    release. npm and DotSlash can then proceed concurrently, reducing total
    release time by about one minute.
  • [codex] publish npm packages concurrently (#27527)
    In https://github.com/openai/codex/actions/runs/27308011621,
    publishing the npm tarballs serially took 147 seconds. Six platform
    packages and the responses API proxy are independent.
    
    Publish those packages concurrently, then publish the root CLI wrapper
    and SDK in dependency order. Individual platform publishes took 19 to
    23 seconds, so this should reduce total release time by nearly two
    minutes.
  • skills: decouple the skills extension from core (#27413)
    ## Why
    
    `ext/skills` currently depends on `codex-core` for two host concerns:
    reading the concrete `Config` type and borrowing core-owned
    model-context fragment types. That coupling prevents the extension from
    being assembled independently above core and leaves context that belongs
    to the skills feature owned by core.
    
    This stacked PR introduces the host boundary needed for the broader
    extension migration while intentionally preserving existing skills
    behavior. It is stacked on #27404.
    
    ## What changed
    
    - Adds a small public `SkillsExtensionConfig` view and makes skills
    installation generic over the host config type.
    - Requires the host to map its config into that view; app-server
    supplies the current `Config` values.
    - Moves the available-skills and selected-skill context fragment
    implementations into `ext/skills`, preserving their roles, markers, and
    rendered bytes.
    - Removes the direct `codex-core` dependency from
    `codex-skills-extension`.
    - Keeps local discovery, invocation, side effects, and the
    `codex-core-skills` compatibility types unchanged for later staged PRs.
    
    ## Behavior
    
    This adds no capability and is intended to have no user-visible or
    model-visible behavior change. The install API and ownership boundary
    change internally; emitted skills context remains byte-for-byte
    compatible.
    
    ## Validation
    
    - Updates the skills extension integration coverage to use a host-owned
    test config.
    - Asserts the complete rendered catalog and selected-skill fragments,
    including their roles and markers.
    - `just bazel-lock-check`
    - Rust tests and Clippy were not run locally per request; CI will run
    them.
  • skills: render catalog locators by authority (#27591)
    ## Why
    
    Hosted skills introduced by #27388 use opaque `skill://` resource
    identifiers, but the skills catalog rendered every locator as a `file`
    and told the model that every skill body lived on disk. That can send
    the model toward filesystem tools for a resource that must instead be
    read through its owning authority.
    
    The catalog should describe how each source is accessed without changing
    the underlying discovery or invocation behavior.
    
    ## What changed
    
    - Render host skills as `file`, executor-owned skills as `environment
    resource`, orchestrator-owned skills as `orchestrator resource`, and
    custom-provider skills as `custom resource`.
    - Update the shared no-alias guidance to describe source locators rather
    than assuming every skill is stored on the host filesystem.
    - Direct orchestrator resources through `skills.list` and `skills.read`,
    and explicitly tell the model not to treat `skill://` identifiers as
    filesystem paths.
    - Preserve the existing filesystem and alias behavior for local skills.
    
    ## Scope
    
    This PR changes only model-visible catalog rendering and guidance. It
    does not change skill discovery, selection, prompt injection, provider
    routing, catalog caching or refresh behavior, resource validation, or
    the `skills.*` tool contract.
    
    ## Verification
    
    - Extended skills-extension coverage for host-file and executor-resource
    labels.
    - Extended the no-executor app-server flow to assert
    orchestrator-resource wording and non-filesystem guidance.
  • test: cover referenced backend skill reads without an executor (#27404)
    ## Why
    
    PR #27388 lets models read child resources referenced by backend plugin
    skills without an executor. The integration fixture should prove that
    real flow: the injected `SKILL.md` advertises a child `skill://`
    resource, and `skills.read` resolves that exact resource through the
    backend provider.
    
    This is stacked on #27388.
    
    ## What changed
    
    - Adds a child-resource link to the backend skill fixture and asserts
    that it reaches model context.
    - Tightens the end-to-end skills test around `skills.list` followed by
    `skills.read` for the referenced resource.
    - Splits the existing app-server `mcpResource/read` coverage into a
    focused test so the generic RPC path remains covered independently.
    
    ## Validation
    
    - Adds app-server integration coverage for both the referenced backend
    skill resource and the generic MCP resource read path.
  • nit: cap error (#27585)
    Just cap an error that could end up in the model context
  • multi-agent: move concurrency guidance into v2 usage hints (#27569)
    ## Why
    
    Native Codex currently teaches multi-agent concurrency through the
    `spawn_agent` tool description, while bridge-driven evals frame the same
    limit as a shared pool of active agent slots. That mismatch makes the
    model-facing story harder to reason about, especially because the
    tool-level wording does not make it explicit that the limit covers the
    whole agent team, including the current agent.
    
    This change gives native Codex the same mental model: tell the root
    agent and subagents how many active slots exist, and remove the separate
    `spawn_agent` limit wording.
    
    ## What changed
    
    - Extend the built-in `multi_agent_v2` root and subagent usage hints
    with shared-slot guidance derived from the resolved
    `max_concurrent_threads_per_session` value.
    - Keep the complete default hints in `MultiAgentV2Config` so initial
    context and forked histories consume the same canonical strings.
    - Drop the redundant `spawn_agent` description text and remove the
    now-unused limit plumbing from the tool spec path.
    
    ## Testing
    
    - `just test -p codex-core usage_hint`
    - `just test -p codex-core
    multi_agent_v2_default_session_thread_cap_counts_root`
    - `just test -p codex-core
    multi_agent_v2_default_usage_hints_use_configured_thread_cap`
    - `just test -p codex-core
    spawn_agent_tool_v2_requires_task_name_and_lists_visible_models`
    - `just test -p codex-core
    multi_agent_feature_selects_one_agent_tool_family`
  • skills: expose remote skill resource tools (#27388)
    ## Why
    
    PR #27387 makes backend plugin skills discoverable and invocable without
    an executor, but resources referenced by those skills still sit behind
    the generic MCP resource surface. The model needs a skills-owned API
    that preserves the provider authority and package boundary instead of
    treating remote resources like local files.
    
    This is stacked on #27387.
    
    ## What
    
    - Adds one `skills` namespace with bounded `list` and `read` tools for
    remote skill providers.
    - Revalidates `authority + package` against the live remote catalog on
    every read, then routes the opaque resource ID back through that
    provider.
    - Allows the backend provider to read canonical child `skill://`
    resources while rejecting cross-package, non-canonical, query, fragment,
    and traversal-shaped URIs.
    - Caps each serialized tool result at 8 KB. Lists are paginated; reads
    return an opaque continuation cursor.
    - Marks the JSON output as external context so memory generation can
    apply its normal suppression policy.
    - Deliberately does not add `skills.search`; that waits for a bounded
    plugin-service search contract.
    
    ## Tool contract
    
    Pseudo-Python matching the wire shape:
    
    ```python
    from typing import Literal, NotRequired, TypedDict
    
    
    class RemoteSkillAuthority(TypedDict):
        kind: Literal["remote"]
        id: str  # e.g. "codex_apps"
    
    
    class RemoteSkill(TypedDict):
        authority: RemoteSkillAuthority
        package: str  # opaque provider-owned package ID
        name: str
        description: str
        main_resource: str  # opaque provider-owned SKILL.md ID
    
    
    class SkillsListParams(TypedDict):
        cursor: NotRequired[str]
    
    
    class SkillsListResult(TypedDict):
        skills: list[RemoteSkill]
        next_cursor: str | None
        warnings: list[str]
        truncated: bool
    
    
    class SkillsReadParams(TypedDict):
        authority: RemoteSkillAuthority  # copied from skills.list
        package: str  # copied from skills.list
        resource: str  # provider-owned child resource ID
        cursor: NotRequired[str]  # copy next_cursor to continue
    
    
    class SkillsReadResult(TypedDict):
        resource: str
        contents: str
        next_cursor: str | None
        truncated: bool
    
    
    class Skills:
        def list(self, params: SkillsListParams) -> SkillsListResult: ...
        def read(self, params: SkillsReadParams) -> SkillsReadResult: ...
    ```
    
    There is one namespace for all remote skills, not one tool or MCP server
    per skill. No resource ID is converted into a filesystem path.
    
    ## Backend dependency
    
    `/ps/mcp` must support direct reads of child resources such as
    `skill://plugin_demo/deploy/references/deploy.md`. This PR implements
    and tests the Codex side of that contract; production child reads remain
    dependent on the corresponding plugin-service support. Search remains
    out of scope until that service exposes a bounded search/resource API.
    
    ## Validation
    
    - Added an app-server integration test covering `skills.list` followed
    by `skills.read` with no executor.
    - Ran `just fmt`.
    - Ran `just bazel-lock-update` and `just bazel-lock-check`.
    - Did not run Rust tests or Clippy locally, per request; CI will run
    them.
  • core: enable remote compaction v2 by default (#27573)
    ## Why
    
    Remote compaction v2 is ready to become the default for providers that
    already support remote compaction. Leaving it behind an
    under-development opt-in keeps eligible sessions on the legacy
    remote-compaction path.
    
    This does not broaden provider eligibility: OpenAI and Azure move to v2,
    while Bedrock and OSS providers retain their existing local-compaction
    behavior.
    
    ## What changed
    
    - Mark `remote_compaction_v2` stable and enable it by default.
    - Make tests that intentionally cover legacy remote compaction
    explicitly disable v2.
    - Update parity coverage so v2 exercises the production default and only
    legacy mode opts out.
    
    ## Verification
    
    - `just test -p codex-core
    auto_compact_runs_after_resume_when_token_usage_is_over_limit
    auto_compact_counts_encrypted_reasoning_before_last_user
    auto_compact_runs_when_reasoning_header_clears_between_turns
    responses_lite_compact_request_uses_lite_transport_contract`
  • skills: cache remote catalog failures per thread (#27403)
    ## Summary
    
    - cache the first remote skill catalog outcome per thread, including
    failures
    - preserve discovery errors as catalog warnings
    - update the existing cache regression test to verify failed discovery
    is attempted once
    
    ## Why
    
    A failed or hanging `codex_apps` `resources/list` call could run once
    while building initial context and immediately again while contributing
    first-turn input. With the discovery timeout, an ordinary Apps turn
    could wait up to 20 seconds before inference and retry again on later
    turns even when no remote skill was mentioned.
    
    Caching a warning-only empty catalog preserves graceful degradation
    while preventing repeated synchronous discovery attempts.
    
    ## Testing
    
    - `just fmt`
    - Tests and Clippy not run per request; CI will validate the change.
  • skills: make backend plugin skills invocable without an executor (#27387)
    ## Why
    
    #27198 made the extension-owned `codex_apps` MCP connection the hosted
    plugin runtime, but its `mcp/skill` resources still bypassed the skills
    extension. App-server could list and read those resources through
    generic MCP APIs, but a thread with no selected environment did not
    expose them in the model's skills catalog or load their `SKILL.md`
    through `$skill`.
    
    Hosted skills should stay remote while using the same typed catalog,
    source authority, deduplication, bounded contextual catalog, and
    selected-skill prompt injection as host and executor skills. They should
    not be downloaded or exposed as ambient filesystem paths.
    
    ## What changed
    
    - Add a session-scoped `McpResourceClient` over the replaceable MCP
    connection manager so resource list/read calls follow startup and
    refresh replacements.
    - Add a `BackendSkillProvider` that pages `codex_apps` resources,
    accepts bounded and validated `mcp/skill` entries, and reads a selected
    skill's `SKILL.md` through the same MCP connection.
    - Register the remote provider in app-server and include it in the
    skills catalog even when a thread has no selected capability roots or
    executor.
    - Contribute hosted skill metadata through the bounded
    `AvailableSkillsInstructions` developer-context path, exclude remote
    entries from per-turn catalog injection, and classify `<skills>`
    messages as contextual developer content so rollback can trim and
    rebuild them correctly.
    
    ## Testing
    
    - Extend the app-server MCP resource integration test with
    `environments: []` to exercise two-page discovery, filter a
    non-`mcp/skill` resource, verify the escaped developer catalog entry and
    user-role `<skill>` fragment containing the fetched `SKILL.md`, and
    preserve generic MCP resource reads.
    - Add core event-mapping coverage that classifies `<skills>` developer
    messages as contextual history.
  • [codex] Tune cloud config cache intervals (#26513)
    ## Summary
    - Increase the cloud config bundle background refresh interval from 5
    minutes to 15 minutes.
    - Increase the local cloud config bundle cache TTL from 30 minutes to 1
    hour.
    
    ## Why
    - Reduce background cloud config fetch frequency while keeping cached
    workspace-managed policies available longer between refreshes.
    
    ## Validation
    - `just fmt`
    - `cargo test -p codex-cloud-config`
  • [codex-analytics] Emit structured compaction codex errors (#27082)
    ## Summary
    - replace raw compaction `error` analytics with `codex_error_kind` and
    `codex_error_http_status_code`
    - derive compaction error telemetry from `CodexErr` using the same
    `CodexErrKind` mapping and HTTP status helper used by turn events
    - remove the pre-compact hook stop reason from the internal compaction
    outcome now that it is no longer emitted as raw analytics text
    
    ## Why
    Compaction `error` was a raw `CodexErr::to_string()` value, which can
    carry free-form provider or user-derived text. Structured Codex error
    fields preserve useful low-cardinality telemetry without sending the raw
    string.
    
    ## Validation
    - `just fmt`
    - `just test -p codex-analytics`
    - `just test -p codex-core
    compact::tests::build_token_limited_compacted_history_appends_summary_message`
    
    Attempted `just test -p codex-core`; the changed crate compiled, but the
    full target failed in unrelated environment-dependent tests such as
    missing helper binaries and shell snapshot timeouts.
  • Use generic search metadata for dynamic tools (#27356)
    ## Why
    
    Dynamic tools maintained a separate search-text builder even though the
    shared tool search path already derives the same metadata from
    `ToolSpec`. Using the shared path removes duplicate behavior before
    adding explicit namespaces.
    
    ## What changed
    
    - Build dynamic-tool search entries with
    `ToolSearchInfo::from_tool_spec`.
    - Remove the custom search-text state and its implementation-only unit
    test.
    
    The old search text included the tool name, its space-separated form,
    description, namespace, and top-level parameter names. The shared
    builder preserves all of those terms and also indexes namespace
    descriptions and nested schema metadata.
    
    ## Test plan
    
    - `just test -p codex-core
    tool_search_returns_deferred_dynamic_tool_and_routes_follow_up_call`
  • [codex-analytics] report cached input tokens for v2 compaction (#27103)
    ## Summary
    
    - add nullable `cached_input_tokens` to the compaction analytics event
    - populate it from response usage for compaction v2
    - leave it `null` for other compaction implementations
    
    This adds visibility into prompt-cache usage for v2 compaction without
    changing compaction behavior.
    
    ## Testing
    
    - `just test -p codex-analytics`
    - `just test -p codex-core
    collect_compaction_output_accepts_additional_output_items`
  • image: preserve metadata when resizing prompt images (#27266)
    ## Summary
    
    - Preserve ICC profiles and EXIF metadata when resizing and re-encoding
    prompt images.
    - Retain EXIF orientation metadata without rotating or otherwise
    modifying the pixel data locally.
    - Support metadata preservation for PNG, JPEG, and WebP outputs.
    - Continue returning the original bytes when an image does not require
    re-encoding.
    
    This intentionally preserves the metadata most important for rendering
    prompt images faithfully. Other format-specific metadata is not copied.
    
    ## Motivation
    
    Client-side resizing previously discarded image metadata during
    re-encoding. This could lose color-profile information and EXIF
    orientation needed by downstream image consumers.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    -  `1` https://github.com/openai/codex/pull/27245
    -  `2` https://github.com/openai/codex/pull/27247
    -  `3` https://github.com/openai/codex/pull/27246
    - 👉 `4` https://github.com/openai/codex/pull/27266
  • [codex] Add context remaining tool (#27518)
    ## Why
    
    The token budget feature can inject remaining-context notices into
    model-visible context, but the model does not have a direct way to ask
    for that same remaining-token fragment on demand.
    
    This PR adds a small model tool for the token budget feature so the
    model can request the current remaining context window message without
    duplicating the fragment format.
    
    ## What changed
    
    - Adds a `get_context_remaining` direct-model tool behind
    `Feature::TokenBudget`.
    - Renders the tool output through `TokenBudgetRemainingContext`,
    matching the existing budget message shape.
    - Registers the tool alongside `new_context` in the token budget tool
    set.
    - Adds integration coverage that verifies the tool is exposed and
    returns the same `<token_budget>` remaining fragment already present in
    context.
    
    ## Validation
    
    - `just test -p codex-core token_budget`
  • [codex] Compact when comp_hash changes (#27520)
    ## Summary
    - snapshot `comp_hash` into `TurnContext` when the turn is created and
    use that snapshot as the downstream source of truth
    - persist the turn hash in rollout context and recover it into
    previous-turn settings during resume and fork replay
    - compact existing history with the previous model only when both
    adjacent turns provide hashes and the values differ
    - record `comp_hash_changed` as the compaction reason
    - cover ordinary transitions, resume, and missing-hash compatibility
    with end-to-end tests
    
    ## Why
    History produced under one compaction-compatible model configuration may
    not be safe to carry directly into another. Compacting at the turn
    boundary converts that history before context updates and the new user
    message are added. Persisting the turn snapshot in `TurnContextItem`
    makes the same protection work after resuming a rollout.
    
    A missing hash is not treated as evidence of incompatibility. `None →
    Some`, `Some → None`, and `None → None` do not trigger compaction; only
    `Some(previous) → Some(current)` with unequal values does.
    
    ## Stack
    - depends on #27532
    - #27532 is based directly on `main`
    
    ## Testing
    - `just test -p codex-core pre_sampling_compact_` — 6 passed
    - `just test -p codex-core
    turn_context_item_uses_turn_context_comp_hash_snapshot` — passed
    - `just fix -p codex-core -p codex-protocol -p codex-analytics -p
    codex-models-manager`
  • [codex] Pass auth mode to plugin manager (#27517)
    ## Summary
    - Add auth mode state to `PluginsManager`.
    - Sync the plugin manager auth mode when `ThreadManager` is created and
    when account auth changes.
    - Route plugin load outcomes through an auth-aware projection hook so
    follow-up plugin filtering can stay inside `core-plugins`.
    
    ## Motivation
    This prepares plugin capability loading to be configured by auth mode,
    such as hiding or exposing app/MCP-backed plugin surfaces based on
    whether the user is using ChatGPT auth or API-key auth, without leaking
    those details outside the plugin manager.
    
    ## Tests
    - `just fmt`
    - `just test -p codex-core-plugins`
    - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p
    codex-core thread_manager::tests`
    - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p
    codex-app-server`
  • core: strip image detail from Responses Lite requests (#27246)
    ## Summary
    
    - Strip image `detail` fields from every Responses Lite request.
    - Apply stripping to message images and function/custom tool-output
    images.
    - Transform only the formatted request copy without mutating stored
    history.
    - Preserve image URLs byte-for-byte, including HTTP(S) URLs, without
    downloading, validating, or resizing them.
    - Preserve all image `detail` fields for non-Responses-Lite models.
    
    ## Motivation
    
    Responses Lite does not support image `detail` tags, so Codex must omit
    them whenever `model_info.use_responses_lite` is enabled. This transport
    requirement is independent of the `resize_all_images` feature.
    
    Stored history retains the original detail values. This keeps
    request-specific formatting isolated from conversation state and
    preserves the information for local image preparation and
    non-Responses-Lite requests.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    -  `1` https://github.com/openai/codex/pull/27245
    -  `2` https://github.com/openai/codex/pull/27247
    - 👉 `3` https://github.com/openai/codex/pull/27246
    -  `4` https://github.com/openai/codex/pull/27266
  • [codex] Add comp_hash to model metadata (#27532)
    ## Summary
    - add optional `comp_hash` metadata to `ModelInfo`
    - update `ModelInfo` fixtures for the shared schema change
    - keep older model responses compatible by defaulting the field to
    `None`
    
    ## Why
    The models endpoint needs an opaque identifier for compaction-compatible
    model configurations. This PR only exposes that value in model metadata;
    it does not add it to turn context or change runtime behavior.
    
    Follow-up #27520 carries the value through turn context and rollouts,
    then uses it to trigger compaction.
    
    ## Stack
    - based directly on `main`
    - replaces #27519, which was accidentally merged into the wrong base
    branch
    - functionality follow-up: #27520
    
    ## Testing
    - `just test -p codex-protocol
    model_info_defaults_availability_nux_to_none_when_omitted`
    - `just fix -p codex-core -p codex-protocol -p codex-analytics -p
    codex-models-manager`
  • feat: add Bedrock API key as a managed auth mode (#27443)
    ## Why
    
    Codex needs to manage Amazon Bedrock API key credentials through the
    existing auth lifecycle instead of introducing a separate auth manager
    or provider-specific credential file. Treating Bedrock API key login as
    a primary auth mode gives it the same persistence, keyring, reload, and
    logout behavior as the existing OpenAI API key and ChatGPT modes.
    
    The credential is valid only for the `amazon-bedrock` model provider.
    OpenAI-compatible providers must reject this auth mode rather than
    treating the Bedrock key as an OpenAI bearer token.
    
    ## What changed
    
    - Added `bedrockApiKey` as an app-server `AuthMode` and
    `CodexAuth::BedrockApiKey` as a primary `AuthManager` mode.
    - Added `BedrockApiKeyAuth`, containing the API key and AWS region, to
    the existing `AuthDotJson` payload stored in `$CODEX_HOME/auth.json` or
    the configured keyring backend.
    - Added `login_with_bedrock_api_key(...)`, parallel to
    `login_with_api_key(...)`, which replaces the current stored login with
    Bedrock credentials.
    - Reused generic auth reload and logout behavior instead of adding a
    Bedrock-specific auth manager or logout path.
    - Updated login restrictions, status reporting, diagnostics, telemetry
    classification, generated app-server schemas, and auth fixtures for the
    new mode.
    - Added explicit errors when Bedrock API key auth is selected with an
    OpenAI-compatible model provider.
    
    This PR establishes managed storage and auth-mode behavior. Routing the
    managed key and region into Amazon Bedrock requests will be in follow-up
    PRs.
  • [codex] Add new context window tool (#27488)
    ## Why
    
    The token budget feature tells the model how much room remains in the
    current context window. When the model decides the current window is no
    longer useful, it needs a way to ask Codex to start over with a fresh
    context window without spending tokens on a compaction summary.
    
    This PR adds that model-requestable escape hatch on top of #27438.
    
    ## What changed
    
    - Added a direct-model-only `new_context` tool behind
    `Feature::TokenBudget`.
    - Stores the tool request on `AutoCompactWindow` and consumes it after
    sampling so the next follow-up request in the same turn starts in the
    new window.
    - Starts the new window as a no-summary compaction checkpoint that
    contains only fresh initial context, not preserved conversation history.
    - Keeps the new window aligned with token-budget startup context,
    including the `Current context window Z` message.
    - Added integration coverage and a snapshot showing the same-turn
    `new_context` flow into a fresh full-context follow-up request.
    
    ## Validation
    
    - `just test -p codex-core token_budget`
  • tools: simplify default tool search text (#27526)
    ## Why
    
    Default tool search text currently derives identity from both `ToolName`
    and `ToolSpec`. For function and namespace specs, this indexes the same
    names more than once and also adds a flattened `{namespace}{name}` token
    that is not model-visible.
    
    ## What changed
    
    - Derive default search text entirely from `ToolSpec` while preserving
    names, descriptions, namespace metadata, and recursive schema metadata.
    - Keep the default search-text builder private and remove the unused
    `ToolName` argument.
    - Add coverage for the exact search text generated for a namespaced tool
    with nested schema metadata.
    
    ## Example
    
    For the `codex_app` namespace and `automation_update` tool (schema terms
    omitted):
    
    - Before: `codex_appautomation_update automation update codex_app
    codex_app Manage Codex automations. automation_update automation update
    ...`
    - After: `codex_app Manage Codex automations. automation_update
    automation update ...`
    
    ## Testing
    
    - `just test -p codex-tools`
  • [codex] Expand hosted web search citation guidance (#27501)
    ## Summary
    
    - Expand the hosted web search prompt with explicit Markdown-link
    citation guidance.
    - Keep internal `turnX` reference IDs out of final responses and place
    citations next to supported claims.
    
    ## Context
    
    
    https://openai.slack.com/archives/C0AU83S0ZQU/p1781133381448499?thread_ts=1780352049.512299&cid=C0AU83S0ZQU
    
    ## Test plan
    
    - Confirmed `codex-rs/ext/web-search/web_run_description.md` exactly
    matches the supplied target prompt.
    - `UV_CACHE_DIR=/tmp/codex-uv-cache
    PATH=/tmp/codex-just/bin:/home/dev-user/.rustup/toolchains/1.95.0-x86_64-unknown-linux-gnu/bin:$PATH
    python3 scripts/format.py --check`
    - `git diff --check`
  • [codex] Add token budget context feature (#27438)
    ## Why
    
    The model should be able to see bounded context-window budget metadata
    when the `token_budget` feature is enabled. The full-window message is
    only injected with full context, while normal turns get a smaller
    follow-up only when reported usage first crosses a budget threshold.
    
    ## What changed
    
    - Added the `TokenBudget` feature flag.
    - Added `<token_budget>` developer fragments for full context-window
    metadata and current-window remaining tokens.
    - Inserted the threshold message during normal turn handling by
    comparing token usage before and after sampling, avoiding persistent
    threshold bookkeeping.
    - Added core integration coverage for full-context-only metadata and
    25/50/75 percent threshold messages.
    
    ## Verification
    
    - `just test -p codex-core token_budget`
    - `git diff --check`
  • Trim TUI legacy telemetry and migration dependencies (#27487)
    ## Why
    
    The TUI still reached through `codex-app-server-client::legacy_core` for
    process telemetry setup and personality migration, exposing core-only
    details after the TUI moved onto the app-server layer.
    
    This is part of our ongoing efforts to whittle away at the legacy_core
    shim that was left over after migrating the TUI to the app server.
    
    This change is just a refactor/rename and should be behavior-neutral and
    low risk.
    
    ## What changed
    
    - expose OTEL provider construction through the app-server client and
    keep the small process/SQLite telemetry adapters local to the TUI
    - collapse personality migration results to the config-reload decision
    the TUI needs
    - remove the `legacy_core::otel_init` and
    `legacy_core::personality_migration` subnamespaces
  • core: resize all history images behind a feature flag (#27247)
    ## Summary
    
    Adds complete client-side image preparation behind the default-off
    `resize_all_images` feature flag.
    
    When enabled, local image producers defer decoding and resizing. Images
    are prepared centrally before insertion into conversation history,
    covering user input, `view_image`, and structured tool-output images.
    
    ## Behavior
    
    - Processes base64 `data:` images in messages and function/custom tool
    outputs.
    - Leaves non-data URLs, including HTTP(S) URLs, unchanged.
    - Applies image-detail budgets:
      - `high` and omitted: 2048px maximum dimension and 2.5K 32px patches.
      - `original`: 6000px maximum dimension and 10K 32px patches.
      - `auto`: uses the same 2048px / 2.5K-patch budget as high.
      - `low`: unsupported and replaced with an actionable placeholder.
    - Preserves original image bytes when no resize or format conversion is
    needed.
    - Enforces the shared 1 GiB encoded and decoded data-URL sanity limits.
    - Replaces only an image that fails preparation, preserving sibling
    content and tool-output metadata.
    - Uses bounded placeholders distinguishing generic processing failures,
    oversized images, and unsupported `low` detail.
    - Prepares resumed and forked history before installing it as live
    history without modifying persisted rollouts.
    
    ## Flag-Off Behavior
    
    When `resize_all_images` is disabled:
    
    - Existing local user-input and `view_image` processing remains
    unchanged.
    - Existing decoding and error behavior remains unchanged.
    - Arbitrary tool-output images are not processed.
    - HTTP(S) image URLs continue to be forwarded unchanged.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    -  `1` https://github.com/openai/codex/pull/27245
    - 👉 `2` https://github.com/openai/codex/pull/27247
    -  `3` https://github.com/openai/codex/pull/27246
    -  `4` https://github.com/openai/codex/pull/27266
  • Add session delete commands in CLI and TUI (#27476)
    ## Summary
    
    The app server exposes `thread/delete`, but users cannot invoke it from
    the CLI or TUI. Because deletion is irreversible, the user-facing
    commands need deliberate confirmation and safer handling of name-based
    targets.
    
    - Add `codex delete <SESSION>` with interactive confirmation,
    restricting `--force` to UUID targets.
    - Resolve exact names across active and archived sessions, including
    renamed sessions, and validate prompted UUID targets before
    confirmation.
    - Add a `/delete` command with a confirmation popup that warns the
    current session and its subagent threads will be permanently deleted.
    
    ## Manual testing
    
    - Deleted by UUID with `--force` and verified the rollout, session-index
    entry, and database row were removed.
    - Exercised name-based confirmation for both cancellation and
    affirmative deletion; cancellation preserved the session and
    confirmation removed it.
    - Verified deletion refuses to proceed without `--force`, while
    `--force` rejects names, including duplicate names.
    - Verified duplicate-name confirmation displays the concrete UUID
    selected.
    - Deleted an archived session by name.
    - Verified an already-missing UUID fails before displaying a
    confirmation prompt.
    - Exercised `/delete` in the TUI: the popup defaults to No, cancellation
    preserves the session, and confirmation deletes the session and exits.
    - Verified that `codex delete` works for both archived and non-archived
    sessions.
  • Remove TUI legacy core test_support dependencies (#27484)
    ## Why
    
    The TUI now sits on the app-server layer, but
    `app-server-client::legacy_core` still exposed core test helpers solely
    for TUI tests. We've been whittling away the remaining dependencies.
    This is the next step on that journey.
    
    There is no functional change — just a refactor, and this affects only
    test code, so it should be low risk.
    
    ## What changed
    
    - remove the `legacy_core::test_support` re-export and call
    model-manager test helpers directly
    - keep the bundled model-preset cache local to TUI test support
    - import constraint types directly from `codex-config`
  • [codex] Remove redundant plugin app auth state (#27465)
    ## Summary
    
    - remove the redundant `needsAuth` field from `AppSummary` and generated
    app-server schemas
    - stop `plugin/read` from querying Apps MCP solely to hydrate unused
    connector auth state
    - preserve `plugin/install.appsNeedingAuth` membership and
    `app/list.isAccessible` as the authentication signals
    
    ## Why
    
    Codex App and TUI do not consume `plugin/read.plugin.apps[].needsAuth`.
    Hydrating it could establish an Apps MCP connection and discover tools
    on a cold `plugin/read` request, adding avoidable latency. The plugin
    APIs are still marked under development, so removing this wire field is
    preferable to retaining a misleading default.
    
    ## Verification
    
    - `just write-app-server-schema`
    - `just fmt`
    - `just test -p codex-app-server-protocol`
    - `just test -p codex-app-server
    plugin_install_uses_remote_apps_needing_auth_response`
    - `just test -p codex-app-server
    plugin_install_returns_apps_needing_auth`
    - `just test -p codex-app-server
    plugin_read_returns_plugin_details_with_bundle_contents`
    - `just test -p codex-tui
    plugin_detail_popup_snapshot_shows_install_actions_and_capability_summaries`
    - `$xin-build` simplify and debug reviews
  • core: cache turn diff rendering (#27489)
    ## Summary
    
    Turn diff updates repeatedly rendered and serialized the entire
    accumulated diff after every `apply_patch`. The event path also rendered
    once before updating the tracker solely to test whether a diff existed.
    In production feedback CODEX-20PW, 2,589 patches across 72 paths
    produced 401 notifications totaling 441 MB, with the hottest paths
    patched 518 and 495 times.
    
    This change:
    
    - replaces the pre-update render with a cheap cached-state check
    - caches each rendered file diff by path and content revision, so an
    update only invokes Myers for affected paths
    - caches the deterministic aggregate diff so event emission and turn
    completion reuse it without recomputation
    - preserves invalidation and net-zero clear notifications
    - applies a 100 ms per-file `similar` timeout; ordinary files complete
    far below this threshold, while pathological rewrites fall back to a
    coarse unified hunk that still represents the exact final contents
    
    The 100 ms deadline bounds synchronous tool-completion latency while
    leaving substantial headroom for normal diffs. The regression test
    applies the fallback diff through the repository's patch parser and
    verifies byte-for-byte final contents.
    
    ## Validation
    
    - `cargo test -p codex-core turn_diff_tracker::tests` (14 passed)
    - `cargo test -p codex-core tools::events::tests` (4 passed)
    - `just fix -p codex-core`
    - `just fmt`
    
    Focused coverage verifies that 42 updates across two files perform 42
    file renders rather than repeatedly rendering the accumulated set,
    unchanged paths are not re-diffed, clear events remain correct, and a
    48,000-line near-total rewrite returns promptly and applies to the exact
    expected result. The full `codex-core` suite was not used as the final
    gate because an unrelated existing multi-agent test hit a stack overflow
    when run during investigation.
    
    ## Bug context
    
    - Sentry feedback: CODEX-20PW
    - Correlation IDs: `019eb2a9-13d2-74e0-b690-27ee224ffb6d`,
    `019e9ad7-09c3-7cb2-b728-ee3acba103ab`
  • [codex] Preserve build-script dependencies in rules_rs annotations (#27322)
    ## Why
    
    Bazel compiles Cargo build scripts in the exec configuration. For
    `openssl-sys`, that means the target-specific optional `openssl-src`
    dependency can disappear when producing musl release binaries, even
    though the build script still needs the vendored source crate.
    
    ## What changed
    
    Patch `rules_rs` to expose its existing unconditional
    `build_script_deps` input through `crate.annotation`, then annotate
    `openssl-sys` with the pinned `openssl-src` target. Target-derived build
    dependencies continue to use the existing selected dependency path.
    
    ## Validation
    
    - `just bazel-lock-check`
    
    Stack: 2 of 6. Follows #27321.
  • [codex-analytics] emit internally started turn events (#27392)
    ## Why
    Currently, the analytics reducer omits `codex_turn_event` for internally
    started subagent turns
    - It uses `TurnState.connection_id` to select app-server client and
    runtime metadata
    - `turn/start` sets this field for client-started turns, while internal
    subagent turns bypass that path
    - Spawned child threads inherit the correct connection, but turn
    emission does not use thread state
    
    ## What Changed
    - Keeps explicit `TurnState.connection_id` authoritative for
    client-started turns
    - Falls back to the matching thread’s inherited connection when the turn
    connection is absent
    - Preserves completeness gates, event schema, and post-emission state
    removal
    - Extends subagent lifecycle test coverage
    
    ## Verification
    - `just test -p codex-analytics` (71 tests passed)
    - `just fix -p codex-analytics`
    - `just fmt`
  • image: add shared data URL preparation utilities (#27245)
    ## Summary
    
    Add shared image-processing primitives needed for centralized image
    preparation in a follow-up PR.
    
    - Add `load_data_url_for_prompt` for decoding and preparing base64 image
    data URLs.
    - Add configurable maximum-dimension and 32px patch-budget resizing.
    - Enforce a 1 GiB sanity limit on both encoded and decoded data-URL
    representations.
    - Preserve original PNG, JPEG, and WebP bytes when resizing is
    unnecessary.
    - Preserve the existing GIF-to-PNG behavior.
    - Move image utility tests into the existing sidecar test module.
    
    ## Behavior
    
    This PR is intended to be runtime behavior-preserving.
    
    Existing production callers continue using
    `PromptImageMode::ResizeToFit` and `PromptImageMode::Original` with
    their existing semantics. The new data-URL entrypoint and configurable
    resize mode have no production callers in this PR; they are used by the
    next PR in the stack.
    
    This PR does not change user-input handling, `view_image`, history
    insertion, request construction, HTTP image URL forwarding, or
    app-server behavior.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    - 👉 `1` https://github.com/openai/codex/pull/27245
    -  `2` https://github.com/openai/codex/pull/27247
    -  `3` https://github.com/openai/codex/pull/27246
    -  `4` https://github.com/openai/codex/pull/27266
  • [codex] Add reusable OTEL gauge instruments (#27057)
    ## Why
    
    Exec-server observability needs current-value measurements in addition
    to counters. The reusable OTEL client should expose that primitive
    without coupling it to exec-server runtime behavior.
    
    ## What changed
    
    - Adds integer gauge instruments, with optional descriptions.
    - Caches gauges by name and description so instrument metadata remains
    part of the declaration identity.
    - Covers gauge values, descriptions, merged attributes, and OTLP HTTP
    export.
    
    This PR only adds the gauge primitive. It does not add second-based
    duration histograms or exec-server adoption.
    
    ## Stack
    
    1. #26091: counter descriptions
    2. **#27057: gauge instruments**
    3. #27058: second-based duration histograms
    
    Related independent coverage: #27059 tests OTLP HTTP log and trace event
    export.
    
    ## Validation
    
    - `just test -p codex-otel`
    - `just fix -p codex-otel`
    - `just fmt`
  • Forward standalone assistant output to realtime (#27319)
    ## Why
    
    When a realtime session is open without an active frontend-model
    handoff, completed Codex assistant messages are currently dropped. That
    prevents the frontend model from hearing orchestrator preambles and
    final responses produced by typed turns or other non-handoff work, which
    makes the two models present as disconnected personas.
    
    Active handoffs already forward each completed assistant message,
    including preambles. This change leaves those V1 and V2 paths intact and
    fills only the no-active-handoff gap.
    
    ## What changed
    
    - Send standalone V1 assistant messages through
    `conversation.handoff.append` with a stable synthetic handoff ID
    - Send standalone V2 assistant messages as normal `[BACKEND]`
    `conversation.item.create` message items, then enqueue `response.create`
    so the frontend model responds
    - Preserve the existing active V1 and V2 transport and completion
    behavior
    - Continue excluding user messages from realtime mirroring
    - Skip empty output and cap each complete context injection, including
    its V2 prefix, at 1,000 tokens
    - Add end-to-end coverage for both wire formats, V2 response creation,
    preambles, final responses, and truncation
    
    ## Test plan
    
    - CI
  • [codex] reuse release artifacts for npm staging (#27312)
    The release job already downloads every workflow artifact into `dist`,
    but npm staging creates a new cache and downloads the six target
    artifacts again.
    
    Reuse `dist` as the staging script's artifact cache while preserving the
    existing download fallback for missing artifacts and standalone callers.
    The script retains ownership of temporary caches but does not delete a
    caller-provided directory.
    
    In https://github.com/openai/codex/actions/runs/27242495616, the
    duplicate
    download transferred 3.3 GiB and took 4 minutes 13 seconds. This should
    reduce total release time by about 4 minutes.