## What changed
Map audio size, data, format, and sample-rate validation failures to `InvalidAudioInput` for HTTP 400 responses and streamed errors. Preserve the provider's message, falling back to `Invalid audio input.` when it is absent or blank.
Classify these errors as non-retryable and expose them as `BadRequest`. Redact their messages in doctor diagnostics and group them as invalid requests in telemetry.
## Testing
Add coverage for all six audio validation codes across HTTP errors, streamed `error` events, and `response.failed` events, checking error classification, message preservation, and the absence of retries. Extend doctor diagnostic redaction coverage for `InvalidAudioInput`.
GitOrigin-RevId: 0a59964bcabd83997bdb32fc9318a5482dac33b0
## What changed
- Recognize `policy_capacity_unavailable` in HTTP and streaming API errors and expose it as `policyCapacityUnavailable` through the app-server protocol and generated bindings.
- Display “Policy-restricted capacity is unavailable. Please try again later.” while preserving overload retry behavior based on `Retry-After`.
- Handle the new error in TUI overload rendering, reviewer retries, and error telemetry.
## Testing
Add coverage for HTTP and streaming error classification, retry advice, WebSocket terminal error attribution, protocol serialization, and TUI rendering with and without an upstream message.
GitOrigin-RevId: 1b9536fba1e11cc891dcf689aee35410d82f5412
## Why
Provider errors with code `model_not_found` should end the turn immediately and preserve the provider's message instead of triggering retries.
## What changed
- Recognize `model_not_found` in HTTP 400, 403, and 404 responses and in streamed `error` and `response.failed` events.
- Preserve the provider message and any available HTTP status, and expose `modelNotFound` through the app-server protocol and generated schemas and SDK types.
## Testing
Add coverage for HTTP classification, statusless stream errors, and terminal failures without retries across HTTP, SSE, and WebSocket responses. Verify that `thread/read` preserves the error reported by the live notification.
GitOrigin-RevId: 88f824ac03c8c9669915b1e40c67b76c08326fbe
## Why
A failed provider catalog refresh could discard model metadata and disable tool search on subsequent turns, even after a successful discovery.
## What changed
Keep the last successful catalog, ETag, and original freshness when refreshes fail without an access rejection. Continue invalidating cached catalogs for HTTP `401`/`403`, rejected refresh tokens, and gateway credentials that require login. Distinguish `GatewayLoginRequired` from login in progress so only the former invalidates the catalog.
Successful empty responses remain authoritative, and cached catalogs remain scoped to the provider and authentication identity.
## Testing
Add regression coverage for catalog preservation across refresh errors and restarts, access rejection invalidation, identity isolation, and tool search and instruction stability on the next turn after a failed refresh.
GitOrigin-RevId: 9dd7c73ac2cc1fd49664efd93b839baa94e05c49
## What changed
- Recognize `sci` and `sci_plus` in authentication, account responses, rate limits, and generated client schemas.
- Treat both plans as workspace accounts eligible for cloud configuration, and use business analytics routes.
- Display “Academic Researchers” and “Academic Researchers Plus” in the TUI and direct users to their admin when usage limits are reached.
## Testing
Add coverage for plan parsing, workspace classification, account and rate-limit responses, cloud configuration eligibility, analytics routing, TUI labels, and usage-limit guidance. Exercise installed-app refresh and listing with `sci_plus` authentication.
GitOrigin-RevId: b51c5df03029b8bc249d44f11b353a7755e7dd04
## Why
Terminal `response.incomplete` errors discard reported token usage. Counting that usage as a new context baseline can also double-count input and trigger unnecessary compaction on the next turn.
## What changed
- Carry the response ID and valid reported usage with incomplete-response errors.
- Record usage for sampling and foreground compaction in cumulative totals, rollout records, budgets, and token-usage contributors without replacing the context baseline. Preserve the original terminal error, including when accounting exhausts the budget or cancellation races the error.
- Charge incomplete background compaction requests to the rollout budget without publishing foreground token usage.
- Ignore missing or malformed usage rather than estimating it.
## Testing
Extend coverage for SSE and WebSocket incomplete responses, rollout usage records, compaction accounting, deferred token-count events, and token-usage contributors. Add regressions for unnecessary compaction on the next turn and background compaction publishing foreground usage.
GitOrigin-RevId: bf1ee6df3912052ab7c19e1c6af8ad3dc4b07675
## Why
Incomplete responses such as `max_output_tokens` were classified as stream errors, allowing retries and compaction model fallback after the response had hit its output limit.
## What changed
Introduce `ResponseIncomplete` errors that preserve the server-provided reason and stop stream processing immediately. Make these errors non-retryable and stop compaction without falling back to the selected model. Record incomplete responses separately in sampler failure metrics.
## Testing
Add regression tests that verify incomplete responses surface a terminal error without retries over SSE and WebSocket, and that compaction stops without retrying or switching models for both local and remote compaction.
GitOrigin-RevId: 6e107d441b9bf03fa47ea47b88eeb94b71a9f729
## Why
Spawn failures can share an error kind and message despite different causes, such as execution and residency capacity limits. Telemetry needs enough detail to distinguish these failures without using error messages or correlation IDs as metric labels.
## What changed
- Add `AgentErrorContext` annotations for capacity limits, registry rejections, runtime availability, and spawn stages. Preserve the first annotation so outer stages retain the more precise failure origin.
- Add bounded `detail` and `error_kind` labels to spawn failure metrics, using `unknown` when no context is available.
- Emit spawn failure trace events with these classifications and the call and turn IDs for both multi-agent versions.
## Testing
Add tests for distinct capacity and registry failure contexts, preservation of manager, fork, and shutdown errors, and metric aggregation across different error messages and correlation IDs. Verify that annotations preserve existing error kinds and user-visible messages.
GitOrigin-RevId: 5bbe3d32f6ce408622f38e559fddeab05b8ccb65
## What changed
Replace `https://chatgpt.com/codex/settings/usage` with
`https://chatgpt.com/settings/usage` in usage-limit errors, the `/status`
card, and backend banner actions. Credit purchase actions retain
`?credits_modal=true`.
## Testing
Update error-message assertions, banner action tests, status hyperlink
assertions, and TUI snapshots to expect the new URL.
GitOrigin-RevId: 1e1db971284a25a781120da30a6dea5ff9c3d957
## Why
Responses overload and exhausted-request errors could terminate despite server retry advice, and WebSocket-to-HTTP fallback could issue a request before the advised deadline.
## What changed
- Allow `ServerOverloaded` and `RetryLimit` errors to retry when server advice is present, within the configured retry budgets.
- Preserve `Retry-After` headers from rejected WebSocket upgrades and wait for the server deadline before falling back to HTTP.
- Keep quota, usage-limit, and policy failures terminal even when they include retry advice.
## Testing
Add coverage for HTTP overload and rate-limit recovery, WebSocket upgrade rejection and fallback timing, retry deadline preservation through error mapping, and retry limits for sampling and manual and automatic compaction.
GitOrigin-RevId: 72d30a9f078652664754dfa971fd7dc7a78f20e8
## Why
Responses stopped by `content_filter` previously followed generic stream-error retry handling without guidance about the block. Retried requests need instructions to explain the limitation and offer a permitted alternative.
## What changed
- Recognize content-filter failures as a distinct error while preserving retryability and the existing public error representation.
- Append developer guidance to the conversation after each sampling block, retaining delivered output and using the existing retry handling.
- Support a model catalog override through `model_messages.content_filter_guidance`. Missing, null, blank, or values exceeding 512 UTF-8 bytes fall back to bundled guidance.
- The bundled guidance tells the model to avoid reproducing or working around blocked content, briefly explain the limitation, offer a permitted alternative, and continue unrelated authorized work.
## Testing
Add a scenario and request-history snapshot covering repeated blocks, catalog guidance on each retry, retained partial output, and eventual completion. Add error-mapping assertions for retryability, public error classification, and error text.
GitOrigin-RevId: ba0c201b3a5a3acf5cfa971332027240e0690225
## Why
Usage limit errors discarded the server-selected window responsible for the limit, leaving turn and compaction analytics unable to distinguish five-hour limits from weekly limits.
## What changed
Preserve optional `limit_window_minutes` from usage limit error responses in `UsageLimitReachedError` and report it as `usage_limit_window_minutes` in turn and compaction events. Accept unsigned integers that fit in `u16`; treat missing, null, malformed, or out-of-range values as unknown. Events for other error kinds report `null`.
## Testing
Add coverage for HTTP and wrapped WebSocket error mapping, analytics serialization and reduction, and app-server propagation to turn and local/remote compaction events. Cases include five-hour and weekly windows, missing or invalid values, and unrelated errors.
GitOrigin-RevId: a32066a007559d91a3c868a756bfd0f976777176
## What changed
- Recognize `promax` in authentication, account responses, and backend rate limits; update generated schemas and client types.
- Display `prolite` as “Pro”, `pro` as “Pro (More)”, and `promax` as “Pro (Max)” in account labels, status, and analytics.
- Include Pro Max in experimental context eligibility, paid-plan tooltips, and usage-limit guidance for purchasing credits.
## Testing
Extend coverage for Pro Max plan parsing, account and rate-limit responses, experimental context eligibility, and plan display names. Update the login token test to expect “Pro (More)”.
GitOrigin-RevId: 197e00fa7a99cbce125c8f1d43a451ec1ed5c1fb
## What changed
- Recognize `flex_unavailable` in HTTP 429 responses and streamed `error` and `response.failed` events. End normal turns without retries and report `Flex capacity unavailable.`
- Expose `flexUnavailable` through the core and app-server protocols and generated schemas and SDK types.
- Keep Flex capacity failures eligible for Guardian review and sampler retries, with a distinct telemetry classification.
- Map unexpected HTTP responses to `HttpConnectionFailed`, preserving their status codes.
## Testing
Add regression coverage for terminal Flex failures over HTTP, SSE, and WebSocket, HTTP 504 status preservation after a stream retry, and protocol serialization. Update Guardian retry and sampler recovery tests to cover Flex failures.
GitOrigin-RevId: f2e03a6d2d36a6d9748c35952e40397f8670d121
## Why
HTTP retries used local backoff even when the server supplied `Retry-After`. Relative retry delays also failed to account for time spent propagating errors or reporting retries.
## What changed
- Parse `Retry-After` delay seconds and HTTP dates into a monotonic deadline captured when response headers arrive.
- Honor that deadline for HTTP retries, falling back to local backoff when valid advice is absent.
- Preserve deadlines through API and Bedrock error mapping, stream retries, and exhausted retry state. Expired advice remains a zero delay instead of triggering local backoff.
## Testing
Add coverage for header parsing, deadline countdown and expiry, error mapping after exhausted HTTP retries, and delayed stream retry notifications. Update Responses and remote compaction tests to verify that HTTP retries honor `Retry-After`.
GitOrigin-RevId: a2eff02946e5524f29e06f7ba1431e3d339261a4
## Why
`invalid_prompt` responses were classified as generic invalid requests, losing the server's specific error classification.
## What changed
Add `InvalidPrompt` variants to the API and core error types and serialize the core protocol classification as `invalid_prompt`. Recognize the code in HTTP 400 responses, wrapped WebSocket errors, and SSE `response.failed` events while preserving server messages and keeping the error non-retryable. Map it to `other` in the app-server v2 protocol.
## Testing
Extend coverage for typed error mapping, missing and blank messages, protocol conversion, and guardian retry handling. Exercise HTTP and SSE failures in core integration tests, asserting the error message, serialized classification, and a single request without retry.
GitOrigin-RevId: 5d9a299a013b06158a4dc27a4054f3dbc5fd0f4d
## What changed
Replace `is_retryable()` with `retry_delay(retry_count)`, which returns `None` for terminal errors and a delay for retryable errors. Prefer server advice when present; otherwise use exponential backoff with jitter. Keep `server_retry_delay()` for callers that need only the server-provided delay.
Route sampling and remote compaction errors through the shared response stream handler, which now checks retryability and obtains the delay together. Preserve server-only retry timing when the retry budget is exhausted.
## Testing
Add coverage for attempt-dependent backoff, zero-duration server advice, and terminal errors that remain non-retryable despite server advice. Update API mapping and provider tests to use the combined retry API.
GitOrigin-RevId: 903f92935e71dea043afe1fad8ccb9389471aa75
## Why
Streaming `bio_policy` failures were classified as generic invalid requests, losing their policy-specific classification.
## What changed
- Add `BioPolicy` errors across the API and core protocol, recognizing streaming failures and HTTP 400 responses, including wrapped WebSocket errors.
- Preserve server messages and use a biological-risk fallback when the message is missing or blank.
- Treat bio policy errors as non-retryable in core and guardian handling, and classify them in diagnostics and telemetry.
- Map `BioPolicy` to `other` in the app-server v2 protocol.
## Testing
Add coverage for error classification, message preservation and fallbacks, HTTP and wrapped WebSocket responses, guardian retry decisions, and app-server conversion. Extend the core integration test to verify that bio policy failures emit a typed error and complete the turn after a single request.
GitOrigin-RevId: 78c2647e8fc8f80297cb8a23fff06ab141099632
## What changed
Replace straight apostrophes with curly apostrophes in usage-limit and high-demand error messages, and update usage-limit test expectations. Document that the context-window error's ASCII prefix is matched by the iOS input-limit classifier.
GitOrigin-RevId: 93484aaf805b9e6f8785fd1b43fe6ff9f1a13efa
## Why
When ordinary included usage is exhausted, eligible users need a way to keep working with the backend-provided Luna Reserve quota and return to their previous model once ordinary usage recovers.
## What changed
- Automatically switch eligible TUI tasks to Luna Reserve after an authoritative account usage read, preserving the prior model and reasoning effort per task.
- Restrict model selection while on Reserve to its supported reasoning levels, keep queued turns on the accepted model, and restore the saved model after a fresh read confirms recovery.
- Surface Reserve usage in the composer and `/status`, and expose `normalModelSlug` in app-server rate-limit snapshots so clients can use the associated model's display metadata without changing the request model.
- Poll account limits more frequently near exhaustion and retain compatibility with app servers that only accept the legacy null request parameters.
## Testing
- Added coverage for Reserve entry, queued-turn handling, task reconstruction, recovery authorization, account changes, model selection, usage rendering, and banner dismissal.
GitOrigin-RevId: 46a435e9531051f8cec3f6a46c4b9f7cfa479747
## Why
App-server clients need the explanation and steering instruction returned with a
misalignment policy violation to offer a user-confirmed continuation. Missing or
incomplete details must continue to behave as a terminal block.
## What changed
- Parse optional misalignment classification, explanation, and steering details
from streamed and HTTP Responses errors and propagate them through core errors.
- Include the details in live app-server `error` and `turn/completed` payloads and
export the corresponding protocol schemas and TypeScript types.
- Keep explanations and steering messages out of serialized rollout events and
redact them from debug output.
- Document how clients can resume with `turn/start` after user confirmation.
## Testing
- Cover streamed, HTTP, and WebSocket-wrapped errors, including malformed and
classification-only details.
- Verify live app-server notifications expose resumable details without writing
the explanation or steering message to the rollout.
GitOrigin-RevId: 329258a444c2cd91d0c57ab1720830b33ddcfac5
## What changed
- Classify `response.failed` events with the `rate_limit_exceeded` code as a distinct retryable error while preserving any parsed retry delay.
- Expose the error as `rateLimitExceeded` through the core protocol and app-server schemas after stream retries are exhausted.
- Preserve the upstream message for TUI display while keeping it out of telemetry summaries.
## Testing
- Cover SSE classification, retry metadata, protocol conversion and serialization, exhausted stream retries, telemetry redaction, and TUI rendering.
GitOrigin-RevId: 02dab4d3477dcd7653a58c49c4bd38687a616579
## What changed
- Recognize `edu_plus` and `edu_pro` as distinct education workspace plans across authentication, backend rate-limit mapping, and app-server account schemas.
- Include both plans in cloud configuration eligibility and use the education usage-limit behavior.
- Display the plans as `Edu Plus` and `Edu Pro` in the TUI status view.
## Testing
- Cover parsing, workspace classification, account and rate-limit responses, cloud configuration eligibility, usage-limit messages, and TUI display names for the new variants.
GitOrigin-RevId: bf8add780ae03a3c6d10c4f4afa0da262c37928e
## What changed
- Recognize `misalignment_policy_violation` errors from response streams and HTTP 400 or 403 responses.
- Preserve the upstream message, use a fallback for blank messages, and treat the error as non-retryable.
- Expose `misalignmentPolicyViolation` through the app-server protocol and generated schemas so turns fail with a typed terminal error.
## Testing
- Cover streamed and HTTP policy violations, fallback messages, retry behavior, and app-server turn completion.
GitOrigin-RevId: fd3485bf0be7bfe3d51c078bbc36a081692fd57f
## What changed
- Track the first duplicate effective tool name while assembling the tool registry, including collisions introduced by external tools, code mode, and tool search.
- When `[features.tool_registry].error_on_tool_collisions` is enabled, fail the turn with a `duplicate tool: <namespace>.<name>` error before sending a model request.
- Continue allowing identical tool names in different namespaces, and preserve the existing collision behavior when strict checking is disabled.
## Testing
- Cover registry collision tracking, strict tool planning across tool sources, namespace isolation, failure before sampling, and pre-sampling compaction.
GitOrigin-RevId: 4cf83538fb513cec0b9c8b567780caaaadd3243d
## What changed
- Recognize `enterprise_cbp_automation` as an Enterprise workspace plan in authentication, backend responses, and app-server account and rate-limit APIs.
- Expose the plan in generated protocol schemas and display it as `Enterprise (Automation)` in account status.
- Apply existing workspace eligibility and Business usage-limit behavior to the new plan.
## Testing
- Cover JWT parsing, plan conversion and serialization, app-server responses, workspace eligibility, usage-limit formatting, and TUI status rendering.
GitOrigin-RevId: d84ae2be3dd60fe398f226e6dc434efe27a387a5
## What changed
- Replace direct `reqwest` error types in `codex-protocol` with
`codex_http_client::HttpError`.
- Build the response-stream error test through
`codex_http_client::HttpResponse`.
- Remove `codex-protocol` from the direct `reqwest` dependency allowlist.
## Testing
- Update the response-stream failure test to cover status and URL propagation
through the shared HTTP response wrapper.
GitOrigin-RevId: 7abcbbe55f994acb13cccefef806a53c7008acde
## What changed
- Recognize `self_serve_business_prolite` across authentication, account and rate-limit APIs, generated schemas, workspace classification, status display, cloud configuration gating, and usage-limit messaging.
- Keep the Python SDK's `PlanType` enum compatible with non-empty string values introduced by newer Codex runtimes while preserving its known constants.
## Testing
- Cover token parsing, account reads and notifications, backend rate-limit mapping, workspace behavior, error formatting, and Python SDK response coercion for the new plan value.
GitOrigin-RevId: 70bc17a7c4ba4028cb10e4333cc1f2ac64da361f
## What changed
- Recognize `ent26` in authentication, account protocol, backend rate-limit
payloads, and generated app-server schemas.
- Treat it as an enterprise workspace plan for cloud-config eligibility and
business-style usage-limit guidance.
- Cover token parsing, serialization, backend mapping, plan classification,
cloud-config access, and usage-limit formatting with tests.
GitOrigin-RevId: 537d897c8b1d80bcdb66d0fd402563fbb8c5a277
## What changed
- Wrap `CodexErrorDetails` and an optional retry delay in `CodexErr`, allowing any mapped error to preserve server-provided retry timing.
- Generate the payload-free `CodexErrKind` classification alongside the error details and reuse it for analytics.
- Update error handling sites to inspect `CodexErr::details()` while preserving existing display, debug, protocol mapping, and retryability behavior.
## Testing
- Add coverage for legacy debug formatting, error-specific retryability, and retry-delay propagation through API error mapping.
GitOrigin-RevId: d3ab8a305f2a2ee21d0c0a8c8c388b06dda9c59a
## Summary
- rename the rollout-budget exhaustion error from
`RolloutBudgetExceeded` to `SessionBudgetExceeded`
- expose the matching app-server v2 wire value as
`sessionBudgetExceeded`
- regenerate JSON/TypeScript schema fixtures and update the app-server
docs and focused tests
This is a naming-only follow-up to #29715 based on [Pavel's review
suggestion](https://github.com/openai/codex/pull/29715#discussion_r3463183480).
Runtime behavior is unchanged.
## Tests
- `just test -p codex-core rollout_budget`
- `just test -p codex-app-server-protocol`
- `just fmt`
- `just write-app-server-schema`
## Summary
- surface shared rollout-budget exhaustion as
`CodexErr::RolloutBudgetExceeded` instead of a generic interrupted turn
- map it through the existing `CodexErrorInfo` and app-server v2
`codexErrorInfo` path
- keep local compaction from retrying after the shared rollout budget is
exhausted
This gives app-server clients a stable `rolloutBudgetExceeded` error
they can classify without guessing from `status="interrupted"`.
## Tests
- `just test -p codex-core rollout_budget`
## Why
Amazon Bedrock returns a `401 Unauthorized` response containing
`Signature expired:` when an AWS credential, including a short-lived
`AWS_BEARER_TOKEN_BEDROCK`, has expired. Codex currently surfaces that
response as a generic `unexpected status` error, which does not explain
how to recover.
Environment-provided bearer tokens cannot be refreshed automatically, so
the error should direct users to refresh their AWS credentials or
replace or remove the environment token and restart Codex. This
classification belongs to the Amazon Bedrock provider so similar
responses from other providers retain their existing behavior.
## What changed
- Add a synchronous `ModelProvider::map_api_error` hook that defaults to
the existing provider-neutral API error mapping, and route model
request, stream, WebSocket, and terminal unauthorized errors through the
active provider.
- Override the hook for Amazon Bedrock. After preserving the structured
status, body, URL, and request metadata, recognize `401` responses
containing `Signature expired:` and attach actionable credential
guidance.
- Keep `codex-protocol` provider-neutral by representing the guidance as
an optional `user_message`. Error rendering prefers this message while
continuing to append the URL, request ID, Cloudflare ray, and
authorization diagnostics.
- Add model-provider coverage for expired signatures and negative cases,
core coverage for provider dispatch after unauthorized recovery, and a
TUI snapshot for the rendered error.
## Testing
Tested with a real request with expired bedrock key:
<img width="962" height="126" alt="Screenshot 2026-06-22 at 3 56 51 PM"
src="https://github.com/user-attachments/assets/7e21cc7c-798e-4662-8467-7f304a2f2b59"
/>
## Why
`openai/openai#947613` adds `X-Codex-Rate-Limit-Reached-Type` for Codex
workspace credit-depletion and spend-cap responses. The CLI currently
reads the adjacent promo header but otherwise renders generic
usage-limit copy, so those responses do not explain the
workspace-specific action the user needs to take.
Backend dependency: https://github.com/openai/openai/pull/947613
## What Changed
- Parse `X-Codex-Rate-Limit-Reached-Type` in the usage-limit error
handling path alongside `x-codex-promo-message`.
- Keep the header value parsing with the shared `RateLimitReachedType`
enum.
- Carry the parsed type on `UsageLimitReachedError` and render
client-owned copy for the four workspace owner/member credit and
spend-cap values.
- Preserve existing promo and plan-based text for absent, generic, or
unknown header values.
- Keep the existing TUI workspace-owner nudge state path unchanged; the
response header only selects the displayed error string.
- Add focused display coverage for all specific type values and the
generic fallback case.
## Test Plan
- Added `usage_limit_reached_error_formats_rate_limit_reached_types`
coverage.
- Not run manually, per request; CI runs validation on the pushed
commit.
## Why
Remote compaction currently sends a unary `POST /responses/compact` and
waits for the full response before replacing history or emitting the
completed `ContextCompaction` item. Unlike normal `/responses` streaming
requests, this unary compact request had no timeout boundary. If the
backend accepts the request and then stalls before returning a body, the
existing request retry policy never sees a transport error, so the
compact turn can remain stuck after the started item with no completion
or actionable error.
That matches the reported hang shape in issues such as #18363, where
logs show `responses/compact` was posted but no corresponding compact
completion followed. A bounded request timeout gives the existing retry
policy a concrete timeout error to retry instead of letting the user sit
indefinitely on automatic context compaction.
## What
- Add a request timeout to legacy `/responses/compact` calls.
- Size that timeout from the provider stream idle timeout with a
conservative multiplier, so the default compact attempt gets 20 minutes
rather than the 5 minute stream idle window.
- Map API transport timeouts to a request timeout error instead of the
child-process timeout message.
## Testing
- Not run (per request; CI will cover).
## Why
`features.multi_agent_v2.max_concurrent_threads_per_session` is meant to
be the MultiAgentV2-specific session thread cap: it counts the root
thread and all open subagent threads. The previous implementation kept
this surface tied to `agents.max_threads`, which made it a global
subagent-only cap and allowed the legacy setting to coexist with
MultiAgentV2.
## What Changed
- Added `max_concurrent_threads_per_session` to
`[features.multi_agent_v2]` with default `4`.
- Removed the `[agents] max_concurrent_threads_per_session` alias to
`agents.max_threads`.
- When MultiAgentV2 is enabled, reject `agents.max_threads` and derive
the existing internal subagent slot limit as
`max_concurrent_threads_per_session - 1`.
- Regenerated `core/config.schema.json` and added coverage for the new
config semantics.
## Result
```
➜ codex git:(jif/clean-multi-agent-v2-config) codex -c features.multi_agent_v2.enabled=true -c features.multi_agent_v2.max_concurrent_threads_per_session=3
╭────────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.0.0) │
│ │
│ model: gpt-5.5 xhigh fast /model to change │
│ directory: ~/code/codex │
╰────────────────────────────────────────────────────╯
Tip: Update Required - This version will no longer be supported starting May 8th. Please upgrade to the latest version (https://github.com/openai/codex/releases/latest) using your preferred package manager.
› Can you try to spawn 4 agents
• I’ll try to start four lightweight agents at once and report exactly what the runtime accepts.
• Spawned Russell [no-apps] (gpt-5.5 xhigh)
└ Spawn probe 1: reply briefly that you started, then wait for further instructions. Do not do any repo work.
• Spawned Descartes [no-apps] (gpt-5.5 xhigh)
└ Spawn probe 2: reply briefly that you started, then wait for further instructions. Do not do any repo work.
• Agent spawn failed
└ Spawn probe 3: reply briefly that you started, then wait for further instructions. Do not do any repo work.
• Agent spawn failed
└ Spawn probe 4: reply briefly that you started, then wait for further instructions. Do not do any repo work.
• The runtime accepted the first two and rejected the next two with agent thread limit reached. I’m checking whether the two accepted probes have returned cleanly, then I’ll close them if needed.
```
---------
Co-authored-by: Codex <noreply@openai.com>
Addresses #17353
Problem: Codex rate-limit fetching failed when the backend returned the
new `prolite` subscription plan type.
Solution: Add `prolite` to the backend/account/auth plan mappings, keep
unknown WHAM plan values decodable, and regenerate app-server plan
schemas.
## 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>