Commit Graph

144 Commits

  • Propagate cache key and service tiers in compact (#21249)
    ## Why
    
    `/responses/compact` should preserve the request-affinity fields that
    apply to the active auth mode. ChatGPT-auth compact requests need the
    effective `service_tier`, and compact requests for every auth mode need
    the stable `prompt_cache_key`, so compaction does not quietly lose
    routing or cache behavior that normal sampling already has.
    
    This follows the request-parity direction from #20719, but keeps the net
    change focused on the compact payload fields needed here.
    
    ## What changed
    
    - Add `service_tier` and `prompt_cache_key` to the compact endpoint
    input payload.
    - Build the remote compact payload from the existing responses request
    builder output so `Fast` still maps to `priority` when compact sends a
    service tier.
    - Pass the turn service tier into remote compaction, but only include it
    in compact payloads for ChatGPT-backed auth.
    - Keep `prompt_cache_key` on compact payloads for all auth modes.
    - Add request-body diff snapshot coverage in
    `core/tests/suite/compact_remote.rs` for:
    - API-key auth reusing `prompt_cache_key` while omitting `service_tier`
    even when `Fast` is configured.
      - ChatGPT auth reusing both `service_tier` and `prompt_cache_key`.
    - Drive the snapshot coverage through five varied turns: plain text,
    multi-part text, tool-call continuation, image+text input, local-shell
    continuation, and final-turn reasoning output.
    
    ## Verification
    
    - Added insta snapshots for compact request-body parity against the last
    normal `/responses` request after five varied turns.
    - Not run locally per repo guidance; relying on GitHub CI for test
    execution.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: add session_id (#20437)
    ## Summary
    
    Related to
    https://openai.slack.com/archives/C095U48JNL9/p1777537279707449
    TLDR:
    We update the meaning of session ids and thread ids:
    * thread_id stays as now
    * session_id become a shared id between every thread under a /root
    thread (i.e. every sub-agent share the same session id)
    
    This PR introduces an explicit `SessionId` and threads it through the
    protocol/client boundary so `session_id` and `thread_id` can diverge
    when they need to, while preserving compatibility for older serialized
    `session_configured` events.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Bound websocket request sends with idle timeout (#20751)
    ## Why
    
    We saw Responses websocket sessions recover only after a long quiet
    period when the server had already logged the websocket as disconnected.
    The normal connect path is already bounded by
    `websocket_connect_timeout_ms`, but the first request send on an
    established websocket reused only the receive-side idle timeout after
    the write completed. If the socket write/pump stalls, the client can sit
    in `ws_stream.send(...)` without reaching the existing receive timeout.
  • realtime: rename provider session ids (#20361)
    ## Summary
    
    Codex is repurposing `session` to mean a thread group, so the realtime
    provider session id should no longer use `session_id` / `sessionId` in
    Codex-facing protocol payloads. This PR renames that provider-specific
    field to `realtime_session_id` / `realtimeSessionId` and intentionally
    breaks clients that still send the old field names.
    
    ## What Changed
    
    - Renamed realtime provider session fields in `ConversationStartParams`,
    `RealtimeConversationStartedEvent`, and `RealtimeEvent::SessionUpdated`.
    - Renamed app-server v2 realtime request and notification fields to
    `realtimeSessionId`.
    - Removed legacy serde aliases for `session_id` / `sessionId`; clients
    must send the new names.
    - Propagated the rename through core realtime startup, app-server
    adapters, codex-api websocket handling, and TUI realtime state.
    - Regenerated app-server protocol schema/TypeScript outputs and updated
    app-server README examples.
    - Kept upstream Realtime API concepts unchanged: provider `session.id`
    parsing and `x-session-id` headers still use the upstream wire names.
    
    ## Testing
    
    - CI is running on the latest pushed commit.
    - Earlier local verification on this PR:
      - `cargo test -p codex-protocol`
    - `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-core
    realtime_conversation`
      - `cargo test -p codex-app-server-protocol`
    - `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-app-server
    realtime_conversation`
    - attempted `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-tui` (local
    linker bus error while linking the test binary)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [rollout-trace] Include x-request-id in rollout trace. (#20066)
    ## Why
    
    Rollout traces need an identifier that can be used to correlate a Codex
    inference with upstream Responses API, proxy, and engine logs. The
    reduced trace model already exposed `upstream_request_id`, but it was
    being populated from the Responses API `response.id`. That value is
    useful for `previous_response_id` chaining, but it is not the transport
    request id that upstream systems key on.
    
    This PR separates those concepts so trace consumers can reliably answer
    both questions:
    
    - which Responses API response did this inference produce?
    - which upstream request handled it?
    
    ## Structure
    
    The change keeps the upstream request id at the same lifecycle level as
    the provider stream:
    
    - `codex-api` captures the `x-request-id` HTTP response header when the
    SSE stream is created and exposes it on `ResponseStream`. Fixture and
    websocket streams set the field to `None` because they do not have that
    HTTP response header.
    - `codex-core` carries that stream-level id into `InferenceTraceAttempt`
    when recording terminal stream outcomes. Completed, failed, cancelled,
    dropped-stream, and pre-response error paths all record the id when it
    is available.
    - `rollout-trace` now records both identifiers in raw terminal inference
    events and response payloads: `response_id` for the Responses API
    `response.id`, and `upstream_request_id` for `x-request-id`.
    - The reducer stores both fields on `InferenceCall`. It also uses
    `response_id` for `previous_response_id` conversation linking, which
    removes the old accidental dependency on the misnamed
    `upstream_request_id` field.
    - Terminal inference reduction now consumes the full terminal payload
    (`InferenceCompleted`, `InferenceFailed`, or `InferenceCancelled`) in
    one place. That keeps status, partial payloads, response ids, and
    upstream request ids consistent across success, failure, cancellation,
    and late stream-mapper events.
    
    ## Why This Shape
    
    `x-request-id` is a property of the HTTP/provider response envelope, not
    an SSE event. Capturing it once in `codex-api` and plumbing it through
    terminal trace recording avoids trying to infer the value from stream
    contents, and it preserves the id even when the stream fails or is
    cancelled after only partial output.
    
    Keeping `response_id` separate from `upstream_request_id` also makes the
    reduced trace model less surprising: `response_id` remains the
    conversation-continuation id, while `upstream_request_id` is the
    operational correlation id for upstream debugging.
    
    ## Validation
    
    The PR updates trace and reducer coverage for:
    
    - reading `x-request-id` from SSE response headers;
    - storing the true upstream request id on completed inference calls;
    - preserving upstream request ids for cancelled and late-cancelled
    inference streams;
    - keeping `previous_response_id` reconstruction tied to `response_id`
    rather than transport request ids.
  • Support end_turn in response.completed (#19610)
    Some providers of Responses API forward a model-defined `end_turn`
    boolean indicating explicitly the model's indication of whether it would
    like to end the turn or to be inferenced again. In this PR, we update
    the sampling loop to use this field correctly if it's set. If the field
    is not set by the provider, we fall back to the existing sampling logic.
  • refactor: route Codex auth through AuthProvider (#18811)
    ## Summary
    
    This PR moves Codex backend request authentication from direct
    bearer-token handling to `AuthProvider`.
    
    The new `codex-auth-provider` crate defines the shared request-auth
    trait. `CodexAuth::provider()` returns a provider that can apply all
    headers needed for the selected auth mode.
    
    This lets ChatGPT token auth and AgentIdentity auth share the same
    callsite path:
    - ChatGPT token auth applies bearer auth plus account/FedRAMP headers
    where needed.
    - AgentIdentity auth applies AgentAssertion plus account/FedRAMP headers
    where needed.
    
    Reference old stack: https://github.com/openai/codex/pull/17387/changes
    
    ## Callsite Migration
    
    | Area | Change |
    | --- | --- |
    | backend-client | accepts an `AuthProvider` instead of a raw
    token/header |
    | chatgpt client/connectors | applies auth through
    `CodexAuth::provider()` |
    | cloud tasks | keeps Codex-backend gating, applies auth through
    provider |
    | cloud requirements | uses Codex-backend auth checks and provider
    headers |
    | app-server remote control | applies provider headers for backend calls
    |
    | MCP Apps/connectors | gates on `uses_codex_backend()` and keys caches
    from generic account getters |
    | model refresh | treats AgentIdentity as Codex-backend auth |
    | OpenAI file upload path | rejects non-Codex-backend auth before
    applying headers |
    | core client setup | keeps model-provider auth flow and allows
    AgentIdentity through provider-backed OpenAI auth |
    
    ## Stack
    
    1. https://github.com/openai/codex/pull/18757: full revert
    2. https://github.com/openai/codex/pull/18871: isolated Agent Identity
    crate
    3. https://github.com/openai/codex/pull/18785: explicit AgentIdentity
    auth mode and startup task allocation
    4. This PR: migrate Codex backend auth callsites through AuthProvider
    5. https://github.com/openai/codex/pull/18904: accept AgentIdentity JWTs
    and load `CODEX_AGENT_IDENTITY`
    
    ## Testing
    
    Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
  • Add safety check notification and error handling (#19055)
    Adds a new app-server notification that fires when a user account has
    been flagged for potential safety reasons.
  • feat: add AWS SigV4 auth for OpenAI-compatible model providers (#17820)
    ## Summary
    
    Add first-class Amazon Bedrock Mantle provider support so Codex can keep
    using its existing Responses API transport with OpenAI-compatible
    AWS-hosted endpoints such as AOA/Mantle.
    
    This is needed for the AWS launch path, where provider traffic should
    authenticate with AWS credentials instead of OpenAI bearer credentials.
    Requests are authenticated immediately before transport send, so SigV4
    signs the final method, URL, headers, and body bytes that `reqwest` will
    send.
    
    ## What Changed
    
    - Added a new `codex-aws-auth` crate for loading AWS SDK config,
    resolving credentials, and signing finalized HTTP requests with AWS
    SigV4.
    - Added a built-in `amazon-bedrock` provider that targets Bedrock Mantle
    Responses endpoints, defaults to `us-east-1`, supports region/profile
    overrides, disables WebSockets, and does not require OpenAI auth.
    - Added Amazon Bedrock auth resolution in `codex-model-provider`: prefer
    `AWS_BEARER_TOKEN_BEDROCK` when set, otherwise use AWS SDK credentials
    and SigV4 signing.
    - Added `AuthProvider::apply_auth` and `Request::prepare_body_for_send`
    so request-signing providers can sign the exact outbound request after
    JSON serialization/compression.
    - Determine the region by taking the `aws.region` config first (required
    for bearer token codepath), and fallback to SDK default region.
    
    ## Testing
    Amazon Bedrock Mantle Responses paths:
    
    - Built the local Codex binary with `cargo build`.
    - Verified the custom proxy-backed `aws` provider using `env_key =
    "AWS_BEARER_TOKEN_BEDROCK"` streamed raw `responses` output with
    `response.output_text.delta`, `response.completed`, and `mantle-env-ok`.
    - Verified a full `codex exec --profile aws` turn returned
    `mantle-env-ok`.
    - Confirmed the custom provider used the bearer env var, not AWS profile
    auth: bogus `AWS_PROFILE` still passed, empty env var failed locally,
    and malformed env var reached Mantle and failed with `401
    invalid_api_key`.
    - Verified built-in `amazon-bedrock` with `AWS_BEARER_TOKEN_BEDROCK` set
    passed despite bogus AWS profiles, returning `amazon-bedrock-env-ok`.
    - Verified built-in `amazon-bedrock` SDK/SigV4 auth passed with
    `AWS_BEARER_TOKEN_BEDROCK` unset and temporary AWS session env
    credentials, returning `amazon-bedrock-sdk-env-ok`.
  • Allow guardian bare allow output (#18797)
    ## Summary
    
    Allow guardian to skip other fields and output only
    `{"outcome":"allow"}` when the command is low risk.
    This change lets guardian reviews use a non-strict text format while
    keeping the JSON schema itself as plain user-visible schema data, so
    transport strictness is carried out-of-band instead of through a schema
    marker key.
    
    ## What changed
    
    - Add an explicit `output_schema_strict` flag to model prompts and pass
    it into `codex-api` text formatting.
    - Set guardian reviewer prompts to non-strict schema validation while
    preserving strict-by-default behavior for normal callers.
    - Update the guardian output contract so definitely-low-risk decisions
    may return only `{"outcome":"allow"}`.
    - Treat bare allow responses as low-risk approvals in the guardian
    parser.
    - Add tests and snapshots covering the non-strict guardian request and
    optional guardian output fields.
    
    ## Verification
    
    - `cargo test -p codex-core guardian::tests::guardian`
    - `cargo test -p codex-core guardian::tests::`
    - `cargo test -p codex-core client_common::tests::`
    - `cargo test -p codex-protocol
    user_input_serialization_includes_final_output_json_schema`
    - `cargo test -p codex-api`
    - `git diff --check`
    
    Note: `cargo test -p codex-core` was also attempted, but this desktop
    environment injects ambient config/proxy state that causes unrelated
    config/session tests expecting pristine defaults to fail.
    
    ---------
    
    Co-authored-by: Dylan Hurd <dylan.hurd@openai.com>
    Co-authored-by: Codex <noreply@openai.com>
  • fix: fully revert agent identity runtime wiring (#18757)
    ## Summary
    
    This PR fully reverts the previously merged Agent Identity runtime
    integration from the old stack:
    https://github.com/openai/codex/pull/17387/changes
    
    It removes the Codex-side task lifecycle wiring, rollout/session
    persistence, feature flag plumbing, lazy `auth.json` mutation,
    background task auth paths, and request callsite changes introduced by
    that stack.
    
    This leaves the repo in a clean pre-AgentIdentity integration state so
    the follow-up PRs can reintroduce the pieces in smaller reviewable
    layers.
    
    ## Stack
    
    1. This PR: full revert
    2. https://github.com/openai/codex/pull/18871: move Agent Identity
    business logic into a crate
    3. https://github.com/openai/codex/pull/18785: add explicit
    AgentIdentity auth mode and startup task allocation
    4. https://github.com/openai/codex/pull/18811: migrate auth callsites
    through AuthProvider
    
    ## Testing
    
    Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
  • chore: document intentional await-holding cases (#18423)
    ## Why
    
    This PR prepares the stack to enable Clippy await-holding lints that
    were left disabled in #18178. The mechanical lock-scope cleanup is
    handled separately; this PR is the documentation/configuration layer for
    the remaining await-across-guard sites.
    
    Without explicit annotations, reviewers and future maintainers cannot
    tell whether an await-holding warning is a real concurrency smell or an
    intentional serialization boundary.
    
    ## What changed
    
    - Configures `clippy.toml` so `await_holding_invalid_type` also covers
    `tokio::sync::{MutexGuard,RwLockReadGuard,RwLockWriteGuard}`.
    - Adds targeted `#[expect(clippy::await_holding_invalid_type, reason =
    ...)]` annotations for intentional async guard lifetimes.
    - Documents the main categories of intentional cases: active-turn state
    transitions that must remain atomic, session-owned MCP manager accesses,
    remote-control websocket serialization, JS REPL kernel/process
    serialization, OAuth persistence, external bearer token refresh
    serialization, and tests that intentionally serialize shared global or
    session-owned state.
    - For external bearer token refresh, documents the existing
    serialization boundary: holding `cached_token` across the provider
    command prevents concurrent cache misses from starting duplicate refresh
    commands, and the current behavior is small enough that an explicit
    expectation is easier to maintain than adding another synchronization
    primitive.
    
    ## Verification
    
    - `cargo clippy -p codex-login --all-targets`
    - `cargo clippy -p codex-connectors --all-targets`
    - `cargo clippy -p codex-core --all-targets`
    - The follow-up PR #18698 enables `await_holding_invalid_type` and
    `await_holding_lock` as workspace `deny` lints, so any undocumented
    remaining offender will fail Clippy.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/18423).
    * #18698
    * __->__ #18423
  • [codex] Send realtime transcript deltas on handoff (#18761)
    ## Summary
    - Track how many realtime transcript entries have already been attached
    to a background-agent handoff.
    - Attach only entries added since the previous handoff as
    `<transcript_delta>` instead of resending the accumulated transcript
    snapshot.
    - Update the realtime integration test so the second delegation carries
    only the second transcript delta.
    
    ## Validation
    - `just fmt`
    - `cargo test -p codex-api`
    - `cargo test -p codex-core
    inbound_handoff_request_sends_transcript_delta_after_each_handoff`
    - `cargo build -p codex-cli -p codex-app-server`
    
    ## Manual testing
    Built local debug binaries at:
    - `codex-rs/target/debug/codex`
    - `codex-rs/target/debug/codex-app-server`
  • Add realtime silence tool (#18635)
    ## Summary
    
    Adds a second realtime v2 function tool, `remain_silent`, so the
    realtime model has an explicit non-speaking action when the
    collaboration mode or latest context says it should not answer aloud.
    This is stacked on #18597.
    
    ## Design
    
    - Advertise `remain_silent` alongside `background_agent` in realtime v2
    conversational sessions.
    - Parse `remain_silent` function calls into a typed
    `RealtimeEvent::NoopRequested` event.
    - Have core answer that function call with an empty
    `function_call_output` and deliberately avoid `response.create`, so no
    follow-up realtime response is requested.
    - Keep the event hidden from app-server/TUI surfaces; it is operational
    plumbing, not user-visible conversation content.
  • Update realtime handoff transcript handling (#18597)
    ## Summary
    
    This PR aims to improve integration between the realtime model and the
    codex agent by sharing more context with each other. In particular, we
    now share full realtime conversation transcript deltas in addition to
    the delegation message.
    
    realtime_conversation.rs now turns a handoff into:
    ```
    <realtime_delegation>
      <input>...</input>
      <transcript_delta>...</transcript_delta>
    </realtime_delegation>
    ```
    
    ## Implementation notes
    
    The transcript is accumulated in the realtime websocket layer as parsed
    realtime events arrive. When a background-agent handoff is requested,
    the current transcript snapshot is copied onto the handoff event and
    then serialized by `realtime_conversation.rs` into the hidden realtime
    delegation envelope that Codex receives as user-turn context.
    
    For Realtime V2, the session now explicitly enables input audio
    transcription, and the parser handles the relevant input/output
    transcript completion events so the snapshot includes both user speech
    and realtime model responses. The delegation `<input>` remains the
    actual handoff request, while `<transcript_delta>` carries the
    surrounding conversation history for context.
    
    Reviewers should note that the transcript payload is intended for Codex
    context sharing, not UI rendering. The realtime delegation envelope
    should stay hidden from the user-facing transcript surface, while still
    being included in the background-agent turn so Codex can answer with the
    same conversational context the realtime model had.
  • [codex] Use AgentAssertion downstream behind use_agent_identity (#17980)
    ## Summary
    
    This is the AgentAssertion downstream slice for feature-gated agent
    identity support, replacing the oversized AgentAssertion slice from PR
    #17807.
    
    It isolates task-scoped downstream AgentAssertion wiring on top of the
    merged PR3.1 work without re-carrying the earlier agent registration,
    task registration, or task-state history.
    
    This PR includes the task-scoped bug-fix call sites from the review:
    generic file upload auth, MCP OpenAI file upload auth, and ARC monitor
    auth. Broader user/control-plane calls move to PR4.1 and PR4.2.
    
    ## Stack
    
    - PR1: https://github.com/openai/codex/pull/17385 - add
    `features.use_agent_identity`
    - PR2: https://github.com/openai/codex/pull/17386 - register agent
    identities when enabled
    - PR3: https://github.com/openai/codex/pull/17387 - register agent tasks
    when enabled
    - PR3.1: https://github.com/openai/codex/pull/17978 - persist and
    prewarm registered tasks per thread
    - PR4: this PR - use task-scoped `AgentAssertion` downstream when
    enabled
    - PR4.1: https://github.com/openai/codex/pull/18094 - introduce
    AuthManager-owned background/control-plane `AgentAssertion` auth
    - PR4.2: https://github.com/openai/codex/pull/18260 - use background
    task auth for additional backend/control-plane calls
    
    ## What Changed
    
    - add AgentAssertion envelope generation in `codex-core`
    - route downstream HTTP and websocket auth through AgentAssertion when
    an agent task is present
    - extend the model-provider auth provider so non-bearer authorization
    schemes can be passed through cleanly
    - make generic file uploads attach the full authorization header value
    - make MCP OpenAI file uploads use the cached thread agent task
    assertion when present
    - make ARC monitor calls use the cached thread agent task assertion when
    present
    
    ## Why
    
    The original PR had drifted ancestry and showed a much larger diff than
    the semantic change actually required. Restacking it onto PR3.1 keeps
    the reviewable surface down to the downstream assertion slice.
    
    ## Validation
    
    - `just fmt`
    - `cargo check -p codex-core -p codex-login -p codex-analytics -p
    codex-app-server -p codex-cloud-requirements -p codex-cloud-tasks -p
    codex-models-manager -p codex-chatgpt -p codex-model-provider -p
    codex-mcp -p codex-core-skills`
    - `cargo test -p codex-model-provider bearer_auth_provider`
    - `cargo test -p codex-core agent_assertion`
    - `cargo test -p codex-app-server remote_control`
    - `cargo test -p codex-cloud-requirements fetch_cloud_requirements`
    - `cargo test -p codex-models-manager manager::tests`
    - `cargo test -p codex-chatgpt`
    - `cargo test -p codex-cloud-tasks`
    - `cargo test -p codex-login agent_identity`
    - `just fix -p codex-core -p codex-login -p codex-analytics -p
    codex-app-server -p codex-cloud-requirements -p codex-cloud-tasks -p
    codex-models-manager -p codex-chatgpt -p codex-model-provider -p
    codex-mcp -p codex-core-skills`
    - `just fix -p codex-app-server`
    - `git diff --check`
  • refactor: use cloneable async channels for shared receivers (#18398)
    This is the first mechanical cleanup in a stack whose higher-level goal
    is to enable Clippy coverage for async guards held across `.await`
    points.
    
    The follow-up commits enable Clippy's
    [`await_holding_lock`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock)
    lint and the configurable
    [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type)
    lint for Tokio guard types. This PR handles the cases where the
    underlying issue is not protected shared mutable state, but a
    `tokio::sync::mpsc::UnboundedReceiver` wrapped in `Arc<Mutex<_>>` so
    cloned owners can call `recv().await`.
    
    Using a mutex for that shape forces the receiver lock guard to live
    across `.await`. Switching these paths to `async-channel` gives us
    cloneable `Receiver`s, so each owner can hold a receiver handle directly
    and await messages without an async mutex guard.
    
    ## What changed
    
    - In `codex-rs/code-mode`, replace the turn-message
    `mpsc::UnboundedSender`/`UnboundedReceiver` plus `Arc<Mutex<Receiver>>`
    with `async_channel::Sender`/`Receiver`.
    - In `codex-rs/codex-api`, replace the realtime websocket event receiver
    with an `async_channel::Receiver`, allowing `RealtimeWebsocketEvents`
    clones to receive without locking.
    - Add `async-channel` as a dependency for `codex-code-mode` and
    `codex-api`, and update `Cargo.lock`.
    
    ## Verification
    
    - The split stack was verified at the final lint-enabling head with
    `just clippy`.
  • [codex] Propagate rate limit reached type (#18227)
    ## Summary
    
    First PR in the split from #17956.
    
    - adds the core/app-server `RateLimitReachedType` shape
    - maps backend `rate_limit_reached_type` into Codex rate-limit snapshots
    - carries the field through app-server notifications/responses and
    generated schemas
    - updates existing constructors/tests for the new optional field
    
    ## Validation
    
    - `cargo test -p codex-backend-client`
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-app-server rate_limits`
    - `cargo test -p codex-tui workspace_`
    - `cargo test -p codex-tui status_`
    - `just fmt`
    - `just fix -p codex-backend-client`
    - `just fix -p codex-app-server-protocol`
    - `just fix -p codex-app-server`
    - `just fix -p codex-tui`
  • feat: add opt-in provider runtime abstraction (#17713)
    ## Summary
    
    - Add `codex-model-provider` as the runtime home for model-provider
    behavior that does not belong in `codex-core`, `codex-login`, or
    `codex-api`.
    - The new crate wraps configured `ModelProviderInfo` in a
    `ModelProvider` trait object that can resolve the API provider config,
    provider-scoped auth manager, and request auth provider for each call.
    - This centralizes provider auth behavior in one place today, and gives
    us an extension point for future provider-specific auth, model listing,
    request setup, and related runtime behavior.
    
    ## Tests
    Ran tests manually to make sure that provider auth under different
    configs still work as expected.
    
    ---------
    
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • Stream apply_patch changes (#17862)
    Adds new events for streaming apply_patch changes from responses api.
    This is to enable clients to show progress during file writes.
    
    Caveat: This does not work with apply_patch in function call mode, since
    that required adding streaming json parsing.
  • [codex] Update realtime V2 VAD silence delay and 1.5 prompt (#18092)
    ## Summary
    
    - set the realtime v2 server VAD silence delay to 500ms
    - update the default realtime 1.5 backend prompt to the v4 text
    - keep the session payload and prompt rendering tests aligned with those
    changes
    
    ## Why
    
    - the VAD change gives the voice path a longer pause before ending the
    user's turn
    - the prompt change makes the default bundled realtime prompt match the
    current v4 content
    
    ## Validation
    
    - `cargo +1.93.0 test -p codex-core realtime_prompt --manifest-path
    /tmp/codex-realtime-v2-vad-prompt-v4/codex-rs/Cargo.toml`
    - `CARGO_TARGET_DIR=/tmp/codex-pr-v4-target cargo +1.93.0 test -p
    codex-api
    realtime_v2_session_update_includes_background_agent_tool_and_handoff_output_item
    --manifest-path
    /tmp/codex-realtime-v2-vad-prompt-v4/codex-rs/Cargo.toml`
    - `CARGO_TARGET_DIR=/tmp/codex-pr-v4-target cargo +1.93.0 test -p
    codex-app-server --test all
    'suite::v2::realtime_conversation::realtime_webrtc_start_emits_sdp_notification'
    --manifest-path /tmp/codex-realtime-v2-vad-prompt-v4/codex-rs/Cargo.toml
    -- --exact`
  • [codex] Route Fed ChatGPT auth through Fed edge (#17151)
    ## Summary
    - parse chatgpt_account_is_fedramp from signed ChatGPT auth metadata
    - add _account_is_fedramp=true to ChatGPT backend-api requests only for
    FedRAMP ChatGPT-auth accounts
  • Clarify realtime v2 context and handoff messages (#17896)
    ## Summary
    - wrap realtime startup context in
    `<startup_context>...</startup_context>` tags
    - prefix V2 mirrored user text and relayed backend text with `[USER]` /
    `[BACKEND]`
    - remove the V2 progress suffix and replace the final V2 handoff output
    with a short completion acknowledgement while preserving the existing V1
    wrapper
    
    ## Testing
    - cargo test -p codex-api
    realtime_v2_session_update_includes_background_agent_tool_and_handoff_output_item
    -- --exact
    - cargo test -p codex-app-server webrtc_v2_background_agent_
    - cargo test -p codex-app-server webrtc_v2_text_input_is_
    - cargo test -p codex-core conversation_user_text_turn_is_
  • Refactor auth providers to mutate request headers (#17866)
    ## Summary
    - Move auth header construction into the
    `AuthProvider::add_auth_headers` contract.
    - Inline `CoreAuthProvider` header mutation in its provider impl and
    remove the shared header-map helper.
    - Update HTTP, websocket, file upload, sideband websocket, and test auth
    callsites to use the provider method.
    - Add direct coverage for `CoreAuthProvider` auth header mutation.
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-api`
    - `cargo test -p codex-core
    client::tests::auth_request_telemetry_context_tracks_attached_auth_and_retry_phase`
    - `cargo test -p codex-core` failed on unrelated/reproducible
    `tools::handlers::multi_agents::tests::multi_agent_v2_followup_task_interrupts_busy_child_without_losing_message`
    
    ---------
    
    Co-authored-by: Celia Chen <celia@openai.com>
  • fix: rename is_azure_responses_wire_base_url to is_azure_responses_provider (#17965)
    ## Why
    
    While reviewing https://github.com/openai/codex/pull/17958, the helper
    name `is_azure_responses_wire_base_url` looked misleading because the
    helper returns true for either the `azure` provider name or an Azure
    Responses `base_url`. The new name makes both inputs part of the
    contract.
    
    ## What
    
    - Rename `is_azure_responses_wire_base_url` to
    `is_azure_responses_provider`.
    - Move the `openai.azure.` marker into
    `matches_azure_responses_base_url` so all base URL marker matching is
    centralized.
    - Keep `Provider::is_azure_responses_endpoint()` behavior unchanged.
    
    ## Verification
    
    - Compared the parent and current implementations.
    `name.eq_ignore_ascii_case("azure")` still returns true before
    consulting `base_url`, `None` still returns false, base URLs are still
    lowercased before marker matching, and the same Azure marker set is
    checked.
    - Ran `cargo test -p codex-api`.
  • Add realtime wire trace logs (#17838)
    - Add trace-only wire logging for realtime websocket request/event text
    payloads and the WebRTC call SDP request.
    - Gate raw realtime logs behind
    `RUST_LOG=codex_api::realtime_websocket::wire=trace` so normal logs stay
    quiet.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add realtime output modality and transcript events (#17701)
    - Add outputModality to thread/realtime/start and wire text/audio output
    selection through app-server, core, API, and TUI.\n- Rename the realtime
    transcript delta notification and add a separate transcript done
    notification that forwards final text from item done without correlating
    it with deltas.
  • Log realtime call location (#17761)
    Add a trace-level log for the realtime call Location header when
    decoding the call id.
  • change realtime tool description (#17699)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • Revert "Option to Notify Workspace Owner When Usage Limit is Reached" (#17391)
    Reverts openai/codex#16969
    
    #sev3-2026-04-10-accountscheckversion-500s-for-openai-workspace-7300
  • Queue Realtime V2 response.create while active (#17306)
    Builds on #17264.
    
    - queues Realtime V2 `response.create` while an active response is open,
    then flushes it after `response.done` or `response.cancelled`
    - requests `response.create` after background agent final output and
    steering acknowledgements
    - adds app-server integration coverage for all `response.create` paths
    
    Validation:
    - `just fmt`
    - `cargo check -p codex-app-server --tests`
    - `git diff --check`
    - CI green
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Rename Realtime V2 tool to background_agent (#17278)
    Rename the Realtime V2 delegation tool and parser constant to
    background_agent, and update the tool description and fixtures to match.
    
    Validation: just fmt; cargo check -p codex-api; git diff --check
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Option to Notify Workspace Owner When Usage Limit is Reached (#16969)
    ## Summary
    - Replace the manual `/notify-owner` flow with an inline confirmation
    prompt when a usage-based workspace member hits a credits-depleted
    limit.
    - Fetch the current workspace role from the live ChatGPT
    `accounts/check/v4-2023-04-27` endpoint so owner/member behavior matches
    the desktop and web clients.
    - Keep owner, member, and spend-cap messaging distinct so we only offer
    the owner nudge when the workspace is actually out of credits.
    
    ## What Changed
    - `backend-client`
    - Added a typed fetch for the current account role from
    `accounts/check`.
      - Mapped backend role values into a Rust workspace-role enum.
    - `app-server` and protocol
      - Added `workspaceRole` to `account/read` and `account/updated`.
    - Derived `isWorkspaceOwner` from the live role, with a fallback to the
    cached token claim when the role fetch is unavailable.
    - `tui`
      - Removed the explicit `/notify-owner` slash command.
    - When a member is blocked because the workspace is out of credits, the
    error now prompts:
    - `Your workspace is out of credits. Request more from your workspace
    owner? [y/N]`
      - Choosing `y` sends the existing owner-notification request.
    - Choosing `n`, pressing `Esc`, or accepting the default selection
    dismisses the prompt without sending anything.
    - Selection popups now honor explicit item shortcuts, which is how the
    `y` / `n` interaction is wired.
    
    ## Reviewer Notes
    - The main behavior change is scoped to usage-based workspace members
    whose workspace credits are depleted.
    - Spend-cap reached should not show the owner-notification prompt.
    - Owners and admins should continue to see `/usage` guidance instead of
    the member prompt.
    - The live role fetch is best-effort; if it fails, we fall back to the
    existing token-derived ownership signal.
    
    ## Testing
    - Manual verification
      - Workspace owner does not see the member prompt.
    - Workspace member with depleted credits sees the confirmation prompt
    and can send the nudge with `y`.
    - Workspace member with spend cap reached does not see the
    owner-notification prompt.
    
    ### Workspace member out of usage
    
    https://github.com/user-attachments/assets/341ac396-eff4-4a7f-bf0c-60660becbea1
    
    ### Workspace owner
    <img width="1728" height="1086" alt="Screenshot 2026-04-09 at 11 48
    22 AM"
    src="https://github.com/user-attachments/assets/06262a45-e3fc-4cc4-8326-1cbedad46ed6"
    />
  • Stop Realtime V2 response.done delegation (#17267)
    Stop parsing Realtime V2 response completion as a Codex handoff;
    delegation stays tied to item completion.\n\nValidation: just fmt; git
    diff --check
    
    Co-authored-by: Codex <noreply@openai.com>
  • Omit empty app-server instruction overrides (#17258)
    ## Summary
    - omit serialized Responses instructions when an app-server base
    instruction override is empty
    - skip empty developer instruction messages and add v2 coverage for the
    empty-override request shape
    
    ## Validation
    - just fmt
    - git diff --check
  • feat: add Codex Apps sediment file remapping (#15197)
    ## Summary
    - bridge Codex Apps tools that declare `_meta["openai/fileParams"]`
    through the OpenAI file upload flow
    - mask those file params in model-visible tool schemas so the model
    provides absolute local file paths instead of raw file payload objects
    - rewrite those local file path arguments client-side into
    `ProvidedFilePayload`-shaped objects before the normal MCP tool call
    
    ## Details
    - applies to scalar and array file params declared in
    `openai/fileParams`
    - Codex uploads local files directly to the backend and uses the
    uploaded file metadata to build the MCP tool arguments locally
    - this PR is input-only
    
    ## Verification
    - `just fmt`
    - `cargo test -p codex-core mcp_tool_call -- --nocapture`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add realtime voice selection (#17176)
    - Add realtime voice selection for realtime/start.
    - Expose the supported v1/v2 voice lists and cover explicit, configured,
    default, and invalid voice paths.
  • Attach WebRTC realtime starts to sideband websocket (#17057)
    Summary:
    - parse the realtime call Location header and join that call over the
    direct realtime WebSocket
    - keep WebRTC starts alive on the existing realtime conversation path
    
    Validation:
    - just fmt
    - git diff --check
    - cargo check -p codex-api
    - cargo check -p codex-core --tests
    - local cargo tests not run; relying on PR CI
  • Add WebRTC transport to realtime start (#16960)
    Adds WebRTC startup to the experimental app-server
    `thread/realtime/start` method with an optional transport enum. The
    websocket path remains the default; WebRTC offers create the realtime
    session through the shared start flow and emit the answer SDP via
    `thread/realtime/sdp`.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat(analytics): generate an installation_id and pass it in responsesapi client_metadata (#16912)
    ## Summary
    
    This adds a stable Codex installation ID and includes it on Responses
    API requests via `x-codex-installation-id` passed in via the
    `client_metadata` field for analytics/debugging.
    
    The main pieces are:
    - persist a UUID in `$CODEX_HOME/installation_id`
    - thread the installation ID into `ModelClient`
    - send it in `client_metadata` on Responses requests so it works
    consistently across HTTP and WebSocket transports
  • [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.
  • 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>
  • chore: clean up argument-comment lint and roll out all-target CI on macOS (#16054)
    ## Why
    
    `argument-comment-lint` was green in CI even though the repo still had
    many uncommented literal arguments. The main gap was target coverage:
    the repo wrapper did not force Cargo to inspect test-only call sites, so
    examples like the `latest_session_lookup_params(true, ...)` tests in
    `codex-rs/tui_app_server/src/lib.rs` never entered the blocking CI path.
    
    This change cleans up the existing backlog, makes the default repo lint
    path cover all Cargo targets, and starts rolling that stricter CI
    enforcement out on the platform where it is currently validated.
    
    ## What changed
    
    - mechanically fixed existing `argument-comment-lint` violations across
    the `codex-rs` workspace, including tests, examples, and benches
    - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` and
    `tools/argument-comment-lint/run.sh` so non-`--fix` runs default to
    `--all-targets` unless the caller explicitly narrows the target set
    - fixed both wrappers so forwarded cargo arguments after `--` are
    preserved with a single separator
    - documented the new default behavior in
    `tools/argument-comment-lint/README.md`
    - updated `rust-ci` so the macOS lint lane keeps the plain wrapper
    invocation and therefore enforces `--all-targets`, while Linux and
    Windows temporarily pass `-- --lib --bins`
    
    That temporary CI split keeps the stricter all-targets check where it is
    already cleaned up, while leaving room to finish the remaining Linux-
    and Windows-specific target-gated cleanup before enabling
    `--all-targets` on those runners. The Linux and Windows failures on the
    intermediate revision were caused by the wrapper forwarding bug, not by
    additional lint findings in those lanes.
    
    ## Validation
    
    - `bash -n tools/argument-comment-lint/run.sh`
    - `bash -n tools/argument-comment-lint/run-prebuilt-linter.sh`
    - shell-level wrapper forwarding check for `-- --lib --bins`
    - shell-level wrapper forwarding check for `-- --tests`
    - `just argument-comment-lint`
    - `cargo test` in `tools/argument-comment-lint`
    - `cargo test -p codex-terminal-detection`
    
    ## Follow-up
    
    - Clean up remaining Linux-only target-gated callsites, then switch the
    Linux lint lane back to the plain wrapper invocation.
    - Clean up remaining Windows-only target-gated callsites, then switch
    the Windows lint lane back to the plain wrapper invocation.
  • 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.
  • don't add transcript for v2 realtime (#15111)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • Add final message prefix to realtime handoff output (#15077)
    - prefix realtime handoff output with the agent final message label for
    both realtime v1 and v2
    - update realtime websocket and core expectations to match
  • [stack 2/4] Align main realtime v2 wire and runtime flow (#14830)
    ## Stack Position
    2/4. Built on top of #14828.
    
    ## Base
    - #14828
    
    ## Unblocks
    - #14829
    - #14827
    
    ## Scope
    - Port the realtime v2 wire parsing, session, app-server, and
    conversation runtime behavior onto the split websocket-method base.
    - Branch runtime behavior directly on the current realtime session kind
    instead of parser-derived flow flags.
    - Keep regression coverage in the existing e2e suites.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • 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