Commit Graph

231 Commits

  • [codex] reduce module visibility (#16978)
    ## Summary
    - reduce public module visibility across Rust crates, preferring private
    or crate-private modules with explicit crate-root public exports
    - update external call sites and tests to use the intended public crate
    APIs instead of reaching through module trees
    - add the module visibility guideline to AGENTS.md
    
    ## Validation
    - `cargo check --workspace --all-targets --message-format=short` passed
    before the final fix/format pass
    - `just fix` completed successfully
    - `just fmt` completed successfully
    - `git diff --check` passed
  • Honor null thread instructions (#16964)
    - Treat explicit null thread instructions as a blank-slate override
    while preserving omitted-field fallback behavior.
    - Preserve null through rollout resume/fork and keep explicit empty
    strings distinct.
    - Add app-server v2 start/fork coverage for the tri-state instruction
    params.
  • [codex] add context-window lineage headers (#16758)
    This change adds client-owned context-window and parent thread id
    headers to all requests to responses api.
  • remove temporary ownership re-exports (#16626)
    Stacked on #16508.
    
    This removes the temporary `codex-core` / `codex-login` re-export shims
    from the ownership split and rewrites callsites to import directly from
    `codex-model-provider-info`, `codex-models-manager`, `codex-api`,
    `codex-protocol`, `codex-feedback`, and `codex-response-debug-context`.
    
    No behavior change intended; this is the mechanical import cleanup layer
    split out from the ownership move.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • extract models manager and related ownership from core (#16508)
    ## Summary
    - split `models-manager` out of `core` and add `ModelsManagerConfig`
    plus `Config::to_models_manager_config()` so model metadata paths stop
    depending on `core::Config`
    - move login-owned/auth-owned code out of `core` into `codex-login`,
    move model provider config into `codex-model-provider-info`, move API
    bridge mapping into `codex-api`, move protocol-owned types/impls into
    `codex-protocol`, and move response debug helpers into a dedicated
    `response-debug-context` crate
    - move feedback tag emission into `codex-feedback`, relocate tests to
    the crates that now own the code, and keep broad temporary re-exports so
    this PR avoids a giant import-only rewrite
    
    ## Major moves and decisions
    - created `codex-models-manager` as the owner for model
    cache/catalog/config/model info logic, including the new
    `ModelsManagerConfig` struct
    - created `codex-model-provider-info` as the owner for provider config
    parsing/defaults and kept temporary `codex-login`/`codex-core`
    re-exports for old import paths
    - moved `api_bridge` error mapping + `CoreAuthProvider` into
    `codex-api`, while `codex-login::api_bridge` temporarily re-exports
    those symbols and keeps the `auth_provider_from_auth` wrapper
    - moved `auth_env_telemetry` and `provider_auth` ownership to
    `codex-login`
    - moved `CodexErr` ownership to `codex-protocol::error`, plus
    `StreamOutput`, `bytes_to_string_smart`, and network policy helpers to
    protocol-owned modules
    - created `codex-response-debug-context` for
    `extract_response_debug_context`, `telemetry_transport_error_message`,
    and related response-debug plumbing instead of leaving that behavior in
    `core`
    - moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and
    `emit_feedback_request_tags_with_auth_env` to `codex-feedback`
    - deferred removal of temporary re-exports and the mechanical import
    rewrites to a stacked follow-up PR so this PR stays reviewable
    
    ## Test moves
    - moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to
    `login/tests/suite/auth_refresh.rs`
    - moved text encoding coverage from
    `core/tests/suite/text_encoding_fix.rs` to
    `protocol/src/exec_output_tests.rs`
    - moved model info override coverage from
    `core/tests/suite/model_info_overrides.rs` to
    `models-manager/src/model_info_overrides_tests.rs`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • core: remove cross-crate re-exports from lib.rs (#16512)
    ## Why
    
    `codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
    which made downstream crates depend on `codex-core` as a proxy module
    instead of the actual owner crate.
    
    Removing those forwards makes crate boundaries explicit and lets leaf
    crates drop unnecessary `codex-core` dependencies. In this PR, this
    reduces the dependency on `codex-core` to `codex-login` in the following
    files:
    
    ```
    codex-rs/backend-client/Cargo.toml
    codex-rs/mcp-server/tests/common/Cargo.toml
    ```
    
    ## What
    
    - Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
    `codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
    `codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
    `codex-tools`, and `codex-utils-path`.
    - Delete the `default_client` forwarding shim in `codex-rs/core`.
    - Update in-crate and downstream callsites to import directly from the
    owning `codex-*` crate.
    - Add direct Cargo dependencies where callsites now target the owner
    crate, and remove `codex-core` from `codex-rs/backend-client`.
  • core: support dynamic auth tokens for model providers (#16288)
    ## Summary
    
    Fixes #15189.
    
    Custom model providers that set `requires_openai_auth = false` could
    only use static credentials via `env_key` or
    `experimental_bearer_token`. That is not enough for providers that mint
    short-lived bearer tokens, because Codex had no way to run a command to
    obtain a bearer token, cache it briefly in memory, and retry with a
    refreshed token after a `401`.
    
    This PR adds that provider config and wires it through the existing auth
    design: request paths still go through `AuthManager.auth()` and
    `UnauthorizedRecovery`, with `core` only choosing when to use a
    provider-backed bearer-only `AuthManager`.
    
    ## Scope
    
    To keep this PR reviewable, `/models` only uses provider auth for the
    initial request in this change. It does **not** add a dedicated `401`
    retry path for `/models`; that can be follow-up work if we still need it
    after landing the main provider-token support.
    
    ## Example Usage
    
    ```toml
    model_provider = "corp-openai"
    
    [model_providers.corp-openai]
    name = "Corp OpenAI"
    base_url = "https://gateway.example.com/openai"
    requires_openai_auth = false
    
    [model_providers.corp-openai.auth]
    command = "gcloud"
    args = ["auth", "print-access-token"]
    timeout_ms = 5000
    refresh_interval_ms = 300000
    ```
    
    The command contract is intentionally small:
    
    - write the bearer token to `stdout`
    - exit `0`
    - any leading or trailing whitespace is trimmed before the token is used
    
    ## What Changed
    
    - add `model_providers.<id>.auth` to the config model and generated
    schema
    - validate that command-backed provider auth is mutually exclusive with
    `env_key`, `experimental_bearer_token`, and `requires_openai_auth`
    - build a bearer-only `AuthManager` for `ModelClient` and
    `ModelsManager` when a provider configures `auth`
    - let normal Responses requests and realtime websocket connects use the
    provider-backed bearer source through the same `AuthManager.auth()` path
    - allow `/models` online refresh for command-auth providers and attach
    the provider token to the initial `/models` request
    - keep `auth.cwd` available as an advanced escape hatch and include it
    in the generated config schema
    
    ## Testing
    
    - `cargo test -p codex-core provider_auth_command`
    - `cargo test -p codex-core
    refresh_available_models_uses_provider_auth_token`
    - `cargo test -p codex-core
    test_deserialize_provider_auth_config_defaults`
    
    ## Docs
    
    - `developers.openai.com/codex` should document the new
    `[model_providers.<id>.auth]` block and the token-command contract
  • codex-tools: extract configured tool specs (#16129)
    ## Why
    
    This continues the `codex-tools` migration by moving another passive
    tool-spec layer out of `codex-core`.
    
    After `ToolSpec` moved into `codex-tools`, `codex-core` still owned
    `ConfiguredToolSpec` and `create_tools_json_for_responses_api()`. Both
    are data-model and serialization helpers rather than runtime
    orchestration, so keeping them in `core/src/tools/registry.rs` and
    `core/src/tools/spec.rs` left passive tool-definition code coupled to
    `codex-core` longer than necessary.
    
    ## What changed
    
    - moved `ConfiguredToolSpec` into `codex-rs/tools/src/tool_spec.rs`
    - moved `create_tools_json_for_responses_api()` into
    `codex-rs/tools/src/tool_spec.rs`
    - re-exported the new surface from `codex-rs/tools/src/lib.rs`, which
    remains exports-only
    - updated `core/src/client.rs`, `core/src/tools/registry.rs`, and
    `core/src/tools/router.rs` to consume the extracted types and serializer
    from `codex-tools`
    - moved the tool-list serialization test into
    `codex-rs/tools/src/tool_spec_tests.rs`
    - added focused unit coverage for `ConfiguredToolSpec::name()`
    - simplified `core/src/tools/spec_tests.rs` to use the extracted
    `ConfiguredToolSpec::name()` directly and removed the now-redundant
    local `tool_name()` helper
    - updated `codex-rs/tools/README.md` so the crate boundary reflects the
    newly extracted tool-spec wrapper and serialization helper
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-configured-spec cargo test -p
    codex-core --lib tools::spec::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-configured-spec cargo test -p
    codex-core --lib client::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
  • Move auth code into login crate (#15150)
    - Move the auth implementation and token data into codex-login.
    - Keep codex-core re-exporting that surface from codex-login for
    existing callers.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat(core, tracing): create turn spans over websockets (#14632)
    ## Description
    
    Dependent on:
    - [responsesapi] https://github.com/openai/openai/pull/760991 
    - [codex-backend] https://github.com/openai/openai/pull/760985
    
    `codex app-server -> codex-backend -> responsesapi` now reuses a
    persistent websocket connection across many turns. This PR updates
    tracing when using websockets so that each `response.create` websocket
    request propagates the current tracing context, so we can get a holistic
    end-to-end trace for each turn.
    
    Tracing is propagated via special keys (`ws_request_header_traceparent`,
    `ws_request_header_tracestate`) set in the `client_metadata` param in
    Responses API.
    
    Currently tracing on websockets is a bit broken because we only set
    tracing context on ws connection time, so it's detached from a
    `turn/start` request.
  • Prefer websockets when providers support them (#13592)
    Remove all flags and model settings.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add auth env observability (#14905)
    CXC-410 Emit Env Var Status with `/feedback` report
    
    Add more observability on top of #14611 
    
    [Unset](https://openai.sentry.io/issues/7340419168/?project=4510195390611458&query=019cfa8d-c1ba-7002-96fa-e35fc340551d&referrer=issue-stream)
    
    [Set](https://openai.sentry.io/issues/7340426331/?project=4510195390611458&query=019cfa91-aba1-7823-ab7e-762edfbc0ed4&referrer=issue-stream)
    <img width="1063" height="610" alt="image"
    src="https://github.com/user-attachments/assets/937ab026-1c2d-4757-81d5-5f31b853113e"
    />
    
    
    ###### Summary
    - Adds auth-env telemetry that records whether key auth-related env
    overrides were present on session start and request paths.
    - Threads those auth-env fields through `/responses`, websocket, and
    `/models` telemetry and feedback metadata.
    - Buckets custom provider `env_key` configuration to a safe
    `"configured"` value instead of emitting raw config text.
    - Keeps the slice observability-only: no raw token values or raw URLs
    are emitted.
    
    ###### Rationale (from spec findings)
    - 401 and auth-path debugging needs a way to distinguish env-driven auth
    paths from sessions with no auth env override.
    - Startup and model-refresh failures need the same auth-env diagnostics
    as normal request failures.
    - Feedback and Sentry tags need the same auth-env signal as OTel events
    so reports can be triaged consistently.
    - Custom provider config is user-controlled text, so the telemetry
    contract must stay presence-only / bucketed.
    
    ###### Scope
    - Adds a small `AuthEnvTelemetry` bundle for env presence collection and
    threads it through the main request/session telemetry paths.
    - Does not add endpoint/base-url/provider-header/geo routing attribution
    or broader telemetry API redesign.
    
    ###### Trade-offs
    - `provider_env_key_name` is bucketed to `"configured"` instead of
    preserving the literal configured env var name.
    - `/models` is included because startup/model-refresh auth failures need
    the same diagnostics, but broader parity work remains out of scope.
    - This slice keeps the existing telemetry APIs and layers auth-env
    fields onto them rather than redesigning the metadata model.
    
    ###### Client follow-up
    - Add the separate endpoint/base-url attribution slice if routing-source
    diagnosis is still needed.
    - Add provider-header or residency attribution only if auth-env presence
    proves insufficient in real reports.
    - Revisit whether any additional auth-related env inputs need safe
    bucketing after more 401 triage data.
    
    ###### Testing
    - `cargo test -p codex-core emit_feedback_request_tags -- --nocapture`
    - `cargo test -p codex-core
    collect_auth_env_telemetry_buckets_provider_env_key_name -- --nocapture`
    - `cargo test -p codex-core
    models_request_telemetry_emits_auth_env_feedback_tags_on_failure --
    --nocapture`
    - `cargo test -p codex-otel
    otel_export_routing_policy_routes_api_request_auth_observability --
    --nocapture`
    - `cargo test -p codex-otel
    otel_export_routing_policy_routes_websocket_connect_auth_observability
    -- --nocapture`
    - `cargo test -p codex-otel
    otel_export_routing_policy_routes_websocket_request_transport_observability
    -- --nocapture`
    - `cargo test -p codex-core --no-run --message-format short`
    - `cargo test -p codex-otel --no-run --message-format short`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix(core): prevent hanging turn/start due to websocket warming issues (#14838)
    ## Description
    
    This PR fixes a bad first-turn failure mode in app-server when the
    startup websocket prewarm hangs. Before this change, `initialize ->
    thread/start -> turn/start` could sit behind the prewarm for up to five
    minutes, so the client would not see `turn/started`, and even
    `turn/interrupt` would block because the turn had not actually started
    yet.
    
    Now, we:
    - set a (configurable) timeout of 15s for websocket startup time,
    exposed as `websocket_startup_timeout_ms` in config.toml
    - `turn/started` is sent immediately on `turn/start` even if the
    websocket is still connecting
    - `turn/interrupt` can be used to cancel a turn that is still waiting on
    the websocket warmup
    - the turn task will wait for the full 15s websocket warming timeout
    before falling back
    
    ## Why
    
    The old behavior made app-server feel stuck at exactly the moment the
    client expects turn lifecycle events to start flowing. That was
    especially painful for external clients, because from their point of
    view the server had accepted the request but then went silent for
    minutes.
    
    ## Configuring the websocket startup timeout
    Can set it in config.toml like this:
    ```
    [model_providers.openai]
    supports_websockets = true
    websocket_connect_timeout_ms = 15000
    ```
  • Apply argument comment lint across codex-rs (#14652)
    ## Why
    
    Once the repo-local lint exists, `codex-rs` needs to follow the
    checked-in convention and CI needs to keep it from drifting. This commit
    applies the fallback `/*param*/` style consistently across existing
    positional literal call sites without changing those APIs.
    
    The longer-term preference is still to avoid APIs that require comments
    by choosing clearer parameter types and call shapes. This PR is
    intentionally the mechanical follow-through for the places where the
    existing signatures stay in place.
    
    After rebasing onto newer `main`, the rollout also had to cover newly
    introduced `tui_app_server` call sites. That made it clear the first cut
    of the CI job was too expensive for the common path: it was spending
    almost as much time installing `cargo-dylint` and re-testing the lint
    crate as a representative test job spends running product tests. The CI
    update keeps the full workspace enforcement but trims that extra
    overhead from ordinary `codex-rs` PRs.
    
    ## What changed
    
    - keep a dedicated `argument_comment_lint` job in `rust-ci`
    - mechanically annotate remaining opaque positional literals across
    `codex-rs` with exact `/*param*/` comments, including the rebased
    `tui_app_server` call sites that now fall under the lint
    - keep the checked-in style aligned with the lint policy by using
    `/*param*/` and leaving string and char literals uncommented
    - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
    registry/git metadata in the lint job
    - split changed-path detection so the lint crate's own `cargo test` step
    runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
    - continue to run the repo wrapper over the `codex-rs` workspace, so
    product-code enforcement is unchanged
    
    Most of the code changes in this commit are intentionally mechanical
    comment rewrites or insertions driven by the lint itself.
    
    ## Verification
    
    - `./tools/argument-comment-lint/run.sh --workspace`
    - `cargo test -p codex-tui-app-server -p codex-tui`
    - parsed `.github/workflows/rust-ci.yml` locally with PyYAML
    
    ---
    
    * -> #14652
    * #14651
  • Add auth 401 observability to client bug reports (#14611)
    CXC-392
    
      [With
      401](https://openai.sentry.io/issues/7333870443/?project=4510195390611458&query=019ce8f8-560c-7f10-a00a-c59553740674&referrer=issue-stream)
      <img width="1909" height="555" alt="401 auth tags in Sentry"
      src="https://github.com/user-attachments/assets/412ea950-61c4-4780-9697-15c270971ee3"
      />
    
    
      - auth_401_*: preserved facts from the latest unauthorized response snapshot
      - auth_*: latest auth-related facts from the latest request attempt
      - auth_recovery_*: unauthorized recovery state and follow-up result
    
    
      Without 401
      <img width="1917" height="522" alt="happy-path auth tags in Sentry"
      src="https://github.com/user-attachments/assets/3381ed28-8022-43b0-b6c0-623a630e679f"
      />
    
      ###### Summary
      - Add client-visible 401 diagnostics for auth attachment, upstream auth classification, and 401 request id / cf-ray correlation.
      - Record unauthorized recovery mode, phase, outcome, and retry/follow-up status without changing auth behavior.
      - Surface the highest-signal auth and recovery fields on uploaded client bug reports so they are usable in Sentry.
      - Preserve original unauthorized evidence under `auth_401_*` while keeping follow-up result tags separate.
    
      ###### Rationale (from spec findings)
      - The dominant bucket needed proof of whether the client attached auth before send or upstream still classified the request as missing auth.
      - Client uploads needed to show whether unauthorized recovery ran and what the client tried next.
      - Request id and cf-ray needed to be preserved on the unauthorized response so server-side correlation is immediate.
      - The bug-report path needed the same auth evidence as the request telemetry path, otherwise the observability would not be operationally useful.
    
      ###### Scope
      - Add auth 401 and unauthorized-recovery observability in `codex-rs/core`, `codex-rs/codex-api`, and `codex-rs/otel`, including feedback-tag surfacing.
      - Keep auth semantics, refresh behavior, retry behavior, endpoint classification, and geo-denial follow-up work out of this PR.
    
      ###### Trade-offs
      - This exports only safe auth evidence: header presence/name, upstream auth classification, request ids, and recovery state. It does not export token values or raw upstream bodies.
      - This keeps websocket connection reuse as a transport clue because it can help distinguish stale reused sessions from fresh reconnects.
      - Misroute/base-url classification and geo-denial are intentionally deferred to a separate follow-up PR so this review stays focused on the dominant auth 401 bucket.
    
      ###### Client follow-up
      - PR 2 will add misroute/provider and geo-denial observability plus the matching feedback-tag surfacing.
      - A separate host/app-server PR should log auth-decision inputs so pre-send host auth state can be correlated with client request evidence.
      - `device_id` remains intentionally separate until there is a safe existing source on the feedback upload path.
    
      ###### Testing
      - `cargo test -p codex-core refresh_available_models_sorts_by_priority`
      - `cargo test -p codex-core emit_feedback_request_tags_`
      - `cargo test -p codex-core emit_feedback_auth_recovery_tags_`
      - `cargo test -p codex-core auth_request_telemetry_context_tracks_attached_auth_and_retry_phase`
      - `cargo test -p codex-core extract_response_debug_context_decodes_identity_headers`
      - `cargo test -p codex-core identity_auth_details`
      - `cargo test -p codex-core telemetry_error_messages_preserve_non_http_details`
      - `cargo test -p codex-core --all-features --no-run`
      - `cargo test -p codex-otel otel_export_routing_policy_routes_api_request_auth_observability`
      - `cargo test -p codex-otel otel_export_routing_policy_routes_websocket_connect_auth_observability`
      - `cargo test -p codex-otel otel_export_routing_policy_routes_websocket_request_transport_observability`
  • feat(app-server, core): add more spans (#14479)
    ## Description
    
    This PR expands tracing coverage across app-server thread startup, core
    session initialization, and the Responses transport layer. It also gives
    core dispatch spans stable operation-specific names so traces are easier
    to follow than the old generic `submission_dispatch` spans.
    
    Also use `fmt::Display` for types that we serialize in traces so we send
    strings instead of rust types
  • Reapply "Pass more params to compaction" (#14298) (#14521)
    This reverts commit 8af97ce4b08fdedadc6037851b5e20cc653e9536.
    
    Confirmed that this runs locally without the previous issues with tool
    use
  • fix: move inline codex-rs/core unit tests into sibling files (#14444)
    ## Why
    PR #13783 moved the `codex.rs` unit tests into `codex_tests.rs`. This
    applies the same extraction pattern across the rest of `codex-rs/core`
    so the production modules stay focused on runtime code instead of large
    inline test blocks.
    
    Keeping the tests in sibling files also makes follow-up edits easier to
    review because product changes no longer have to share a file with
    hundreds or thousands of lines of test scaffolding.
    
    ## What changed
    - replaced each inline `mod tests { ... }` in `codex-rs/core/src/**`
    with a path-based module declaration
    - moved each extracted unit test module into a sibling `*_tests.rs`
    file, using `mod_tests.rs` for `mod.rs` modules
    - preserved the existing `cfg(...)` guards and module-local structure so
    the refactor remains structural rather than behavioral
    
    ## Testing
    - `cargo test -p codex-core --lib` (`1653 passed; 0 failed; 5 ignored`)
    - `just fix -p codex-core`
    - `cargo fmt --check`
    - `cargo shear`
  • Responses: set x-client-request-id as convesration_id when talking to responses (#14312)
    Right now we're sending the header session_id to responses which is
    ignored/dropped. This sets a useful x-client-request-id to the
    conversation_id.
  • Pass more params to compaction (#14247)
    Pass more params to /compact. This should give us parity with the
    /responses endpoint to improve caching.
    
    I'm torn about the MCP await. Blocking will give us parity but it seems
    like we explicitly don't block on MCPs. Happy either way
  • chore(otel): rename OtelManager to SessionTelemetry (#13808)
    ## Summary
    This is a purely mechanical refactor of `OtelManager` ->
    `SessionTelemetry` to better convey what the struct is doing. No
    behavior change.
    
    ## Why
    
    `OtelManager` ended up sounding much broader than what this type
    actually does. It doesn't manage OTEL globally; it's the session-scoped
    telemetry surface for emitting log/trace events and recording metrics
    with consistent session metadata (`app_version`, `model`, `slug`,
    `originator`, etc.).
    
    `SessionTelemetry` is a more accurate name, and updating the call sites
    makes that boundary a lot easier to follow.
    
    ## Validation
    
    - `just fmt`
    - `cargo test -p codex-otel`
    - `cargo test -p codex-core`
  • image-gen-core (#13290)
    Core tool-calling for image-gen, handles requesting and receiving logic
    for images using response API
  • Add under-development original-resolution view_image support (#13050)
    ## Summary
    
    Add original-resolution support for `view_image` behind the
    under-development `view_image_original_resolution` feature flag.
    
    When the flag is enabled and the target model is `gpt-5.3-codex` or
    newer, `view_image` now preserves original PNG/JPEG/WebP bytes and sends
    `detail: "original"` to the Responses API instead of using the legacy
    resize/compress path.
    
    ## What changed
    
    - Added `view_image_original_resolution` as an under-development feature
    flag.
    - Added `ImageDetail` to the protocol models and support for serializing
    `detail: "original"` on tool-returned images.
    - Added `PromptImageMode::Original` to `codex-utils-image`.
      - Preserves original PNG/JPEG/WebP bytes.
      - Keeps legacy behavior for the resize path.
    - Updated `view_image` to:
    - use the shared `local_image_content_items_with_label_number(...)`
    helper in both code paths
      - select original-resolution mode only when:
        - the feature flag is enabled, and
        - the model slug parses as `gpt-5.3-codex` or newer
    - Kept local user image attachments on the existing resize path; this
    change is specific to `view_image`.
    - Updated history/image accounting so only `detail: "original"` images
    use the docs-based GPT-5 image cost calculation; legacy images still use
    the old fixed estimate.
    - Added JS REPL guidance, gated on the same feature flag, to prefer JPEG
    at 85% quality unless lossless is required, while still allowing other
    formats when explicitly requested.
    - Updated tests and helper code that construct
    `FunctionCallOutputContentItem::InputImage` to carry the new `detail`
    field.
    
    ## Behavior
    
    ### Feature off
    - `view_image` keeps the existing resize/re-encode behavior.
    - History estimation keeps the existing fixed-cost heuristic.
    
    ### Feature on + `gpt-5.3-codex+`
    - `view_image` sends original-resolution images with `detail:
    "original"`.
    - PNG/JPEG/WebP source bytes are preserved when possible.
    - History estimation uses the GPT-5 docs-based image-cost calculation
    for those `detail: "original"` images.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    - 👉 `1` https://github.com/openai/codex/pull/13050
    -  `2` https://github.com/openai/codex/pull/13331
    -  `3` https://github.com/openai/codex/pull/13049
  • add fast mode toggle (#13212)
    - add a local Fast mode setting in codex-core (similar to how model id
    is currently stored on disk locally)
    - send `service_tier=priority` on requests when Fast is enabled
    - add `/fast` in the TUI and persist it locally
    - feature flag
  • Propagate session ID when compacting (#12802)
    We propagate the session ID when sending requests for inference but we
    don't do the same for compaction requests. This makes it hard to link
    compaction requests to their session for debugging purposes
  • Send warmup request (#11258)
    Send a request with `generate: falls` but a full set of tools and
    instructions to pre-warm inference.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Prefer v2 websockets if available (#12428)
    And also cleanup settings flow to avoid reading many separate flags.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Reuse connection between turns (#12294)
    Add a pool of one to the model client to reuse connections across turns.
  • Hide the first websocket retry (#11548)
    Sometimes connection needs to be quickly reestablished, don't produce an
    error for that.
  • Do not attempt to append after response.completed (#11402)
    Completed responses are fully done, and new response must be created.
  • chore: rename disable_websockets -> websockets_disabled (#11420)
    `disable_websockets()` is confusing because its a getter. rename for
    clarity
  • Do not resend output items in incremental websockets connections (#11383)
    In the incremental websocket output items are already part of the
    context, no need to send them again and duplicate.
  • Prefer websocket transport when model opts in (#11386)
    Summary
    - add a `prefer_websockets` field to `ModelInfo`, defaulting to `false`
    in all fixtures and constructors
    - wire the new flag into websocket selection so models that opt in
    always use websocket transport even when the feature gate is off
    
    Testing
    - Not run (not requested)
  • Compare full request for websockets incrementality (#11343)
    Tools can dynamically change mid-turn now. We need to be more thorough
    about reusing incremental connections.
  • Remove ApiPrompt (#11265)
    Keep things simple and build a full Responses API request request right
    in the model client
  • memories: add extraction and prompt module foundation (#11200)
    ## Summary
    - add the new `core/src/memories` module (phase-one parsing, rollout
    filtering, storage, selection, prompts)
    - add Askama-backed memory templates for stage-one input/system and
    consolidation prompts
    - add module tests for parsing, filtering, path bucketing, and summary
    maintenance
    
    ## Testing
    - just fmt
    - cargo test -p codex-core --lib memories::
  • Move warmup to the task level (#11216)
    Instead of storing a special connection on the client level make the
    regular task responsible for establishing a normal client session and
    open a connection on it.
    
    Then when the turn is started we pass in a pre-established session.
  • Fallback to HTTP on UPGRADE_REQUIRED (#10824)
    Allow the server to trigger a connection downgrade in case the protocol
    changes in incompatible ways.
  • Support alternative websocket API (#10861)
    **Test plan**
    
    ```
    cargo build -p codex-cli && RUST_LOG='codex_api::endpoint::responses_websocket=trace,codex_core::client=debug,codex_core::codex=debug' \
      ./target/debug/codex \
        --enable responses_websockets_v2 \
        --profile byok \
        --full-auto
    ```