## What changed
- Render the first line of a completed hook warning in the hook header using
`says:`, with any remaining lines indented below it.
- Keep the existing hook header when no warning is present and avoid rendering
warning entries a second time in the output body.
- Update hook event snapshots and the multiline warning test for the new layout.
GitOrigin-RevId: 291b556daf3b6fb64a99b090a6df1a222a18a736
## Why
Pending Guardian review state could outlive an interrupted or completed turn,
leaving stale review details visible during a following goal turn.
## What changed
- Clear pending Guardian reviews during both turn completion and finalization.
- Restore an active MCP startup header after cleanup, falling back to `Working`
when no MCP server is starting.
## Testing
Added coverage for interrupted and completed turns, including goal continuation
and overlapping MCP startup status.
GitOrigin-RevId: a15ed81a5d6005e9294089f4424a8dedbc6e9cb5
## Why
The TUI already receives skill metadata from the app-server protocol, but converted it into the core-skills model before using it.
## What changed
- Use `codex_app_server_protocol::SkillMetadata` throughout skill toggles, mentions, and input submission.
- Remove the protocol-to-core conversion and the TUI's `codex-core-skills` dependency.
GitOrigin-RevId: 43d43d74bfb67fc21ef11a0ca0592aa44b89a122
## What changed
- Add one-shot composer and status-line transitions when the active reasoning effort changes to Max or Ultra.
- Keep a tier-specific prompt accent after the transition, including a distinct Ultra prompt glyph.
- Preserve drafts and footer priority, avoid replaying effects for restored or unchanged settings, and disable motion when animations or sufficient terminal color support are unavailable.
## Testing
- Add unit and snapshot coverage for animation frames, prompt accents, status-line transitions, narrow layouts, terminal palettes, restored sessions, and reduced-motion behavior.
GitOrigin-RevId: 6da1d501d228d0cf1144b3d211d5d1304a06f447
## What changed
- Encapsulate aggregated command output behind APIs for total and retained line
counts, reversible preview iteration, and full transcript iteration.
- Build truncated command previews from the retained head and tail lines while
preserving the logical omitted-line count.
- Cover head/tail rendering for long streamed agent and user-shell output.
GitOrigin-RevId: 54b23a19e4639e24c5e4778082edbbc6484ecf80
## Why
Sizing, rendering, and cursor placement can query the same chat widget layout
multiple times in one frame, repeatedly measuring active transcript cells.
## What changed
- Build one chat widget renderable tree per frame and reuse it for sizing,
rendering, and cursor placement.
- Cache each flex child's desired height by width for the lifetime of that tree.
- Reuse the bottom pane's renderable directly instead of forwarding each
renderable operation through a wrapper.
## Testing
- Verify flex layouts measure a child once across frame passes and remeasure it
when the width changes.
- Verify a chat widget frame measures its active transcript cell once.
GitOrigin-RevId: 5ad1a6711f4011c699b5d002b13dc3319cb4db8e
## What changed
- Move lifecycle and approval payloads into either the interrupt queue or the
immediate handler instead of cloning them for both branches.
- Borrow MCP elicitation request metadata while constructing the corresponding
form, and consume apply-patch changes after collecting notification paths.
## Testing
- Add a history replay test confirming deferred MCP start and completion events
remain FIFO after streaming finishes.
GitOrigin-RevId: 84ed34f6ff173463a1da016dc140405392c0ba45
## Why
App-server command output deltas populate an exec cell before the command
finishes. Treating the presence of output as completion can therefore mark a
streaming command inactive too early and mishandle it when the turn is
interrupted.
## What changed
- Use the recorded duration, which is set when a command ends, as the exec
call's completion marker.
- Preserve streamed output when marking unfinished calls as failed and render
status lines only after completion.
- Keep a single aggregated output representation and render truncated output
without collecting every line first.
- Append grouped exploration calls in place and coalesce adjacent reads while
rendering without cloning the calls.
## Testing
- Add snapshots covering active streamed output, transcript output, and the
resulting history entry after interruption.
- Add coverage for truncating newline-dense output.
GitOrigin-RevId: 420ac1e5fe1b9fcdbdaa5a8998f3e43a5b720254
## What changed
- Redraw assistant and plan stream tails only when a completed line changes the visible tail.
- Cache the first reasoning header and update the status indicator only when its visible state changes, while restoring the cached header if the indicator is recreated.
- Keep regular commit ticks able to clear stale stream tails.
## Testing
- Add coverage for unchanged partial deltas, changed newline-delimited tails, reasoning-header redraws, recreated status indicators, stale plan tails, and history-line draw scheduling.
GitOrigin-RevId: 9016175f97ef2db2edc2fd5ba13a4d731dc2d98c
## What changed
Update normal-mode reasoning shortcuts to emit only an
`UpdateReasoningEffort` event instead of reapplying the current model alongside
the new effort.
Extend the shortcut tests to verify that both increasing and decreasing
reasoning effort leave the model unchanged.
GitOrigin-RevId: cf5206a3a8e0a0bf66ecc2d0bfcc1ba44c98fead
## Why
Audio variants were available in the user-input protocol but were replaced with unsupported-input placeholders instead of being sent to the model.
## What changed
- Serialize audio data URLs as `input_audio` content and convert local `wav`, `mp3`, `m4a`, `webm`, and `ogg` files to labeled data URLs.
- Validate and canonicalize base64 audio before requests, enforce the 50 MiB input limit, and replace invalid, unsupported, or oversized audio with explanatory text.
- Preserve audio attachments when mapping response items back to user-message events and document the app-server input variants.
## Testing
- Add unit coverage for local-file conversion, data URL validation, size and format errors, event mapping, and attachment extraction.
- Add client tests that verify data URL and local audio payloads sent to the Responses API.
GitOrigin-RevId: f72cd6b6e43ab12757eeb47621b1d670594ac7d9
## Why
Assistant-authored inline visualizations need a terminal fallback that lets users open generated artifacts in a browser.
## What changed
- Recognize `::codex-inline-vis{file="..."}` directives in assistant Markdown and replace them with browser links during streaming, finalized history rendering, and local transcript previews.
- Materialize visualization fragments in sandboxed viewer documents with a content security policy, while restricting artifacts to HTML files within the thread's visualization directory and limiting their size.
- Show an explicit unavailable message for invalid or missing artifacts, hide incomplete streaming directives, and preserve directive text in code blocks and user Markdown.
- Add a trusted file-link path for generated viewers without enabling arbitrary `file:` links in Markdown.
## Testing
Add coverage for directive rewriting, streaming and replay, artifact validation, sandboxed viewer generation, trusted terminal hyperlinks, and literal preservation.
GitOrigin-RevId: a666b4ebc82bb5798ad45bd137fd815d538e1de2
## What changed
- Add remote and local audio variants to core and app-server user inputs, including generated JSON and TypeScript schemas.
- Preserve audio fields when converting app-server inputs and response content into thread items.
- Keep unsupported audio out of model requests, TUI rendering, text extraction, and truncated tool output, using explicit text placeholders where audio is submitted as a model input.
## Testing
- Cover app-server media conversion, unsupported-input placeholders, TUI omission, and tool-output truncation.
GitOrigin-RevId: 16152bf3af674575ce569764a8b472e032e7569d
## Why
Reverse search fetched persistent history one entry at a time, making a deep or unsuccessful search require a lookup for every older entry.
## What changed
- Keep the newest-entry probe lightweight, then scan older persistent history in bounded batches.
- Cache batch results by absolute offset and preserve continuation cursors across repeated searches.
- Ignore stale responses, retry failed batch reads a bounded number of times, and restore the draft without reporting a false “no match” state when history is unavailable.
## Testing
- Cover batch continuation, caching after query changes or cancellation, stale metadata, retry exhaustion, and thread routing.
- Verify that scanning 1,024 entries uses one single-entry lookup and eight batch lookups.
GitOrigin-RevId: efc791fcbd5290050af703dd31c5c21b33240e23
## What changed
- Add nullable `mustShowInstallationInterstitial` metadata to app-server
`PluginSummary` responses.
- Preserve the remote service value through catalog, installed-plugin cache,
list, read, and share-list paths.
- Return `null` for local plugins and remote responses that omit the field so
clients can fail closed when the policy is unavailable.
## Testing
- Cover `true`, `false`, and missing values across remote summary paths and
app-server plugin endpoints.
GitOrigin-RevId: db79702ee2bfa800a9910d64d933bcabecb3ce70
## What changed
- Add the `SessionEnd` hook event to hook configuration, protocol schemas, analytics, and the hooks browser.
- Run matching hooks for root threads during shutdown, including app-server archive, delete, idle unload, and graceful shutdown. Flush the transcript first and provide the session ID, transcript path, working directory, and `reason: "other"`.
- Keep teardown bounded: hook output is advisory, the default timeout is one second, configured timeouts are capped at three seconds, and async hooks run synchronously with a warning.
## Testing
- Cover transcript availability, matcher selection, timeout normalization, ignored control output, subagent exclusion, archive/delete ordering, and graceful shutdown of multiple loaded threads.
GitOrigin-RevId: 5d19a658677a137caf836ed5042dcb43f5eb6d1a
## Why
Selecting a usage-limit reset from the picker immediately started redemption,
leaving no opportunity to verify the choice.
## What changed
- Open a separate confirmation popup before redeeming a selected reset, with
`No, go back` selected by default.
- Show backend-provided reset titles and descriptions in the picker and
confirmation, with generic fallback copy when those details are absent.
- Ignore duplicate or stale confirmation and redemption events, while retaining
the idempotency key needed to retry a failed redemption.
## Testing
- Added coverage for confirmation, cancellation, backend copy, duplicate and
stale events, successful redemption, and retry behavior.
GitOrigin-RevId: 828945f99f06e8c73941fd864e4aa9ac52729f98
## Why
Multi-agent V2 spawned threads are controlled by their parent and reject direct
app-server input. The TUI should expose that ownership instead of presenting an
input flow that the server will reject.
## What changed
- Add the experimental `Thread.canAcceptDirectInput` capability for loaded
threads and populate it from the same policy used to validate `turn/start`
and `turn/steer`. Stored, unloaded threads report `null`.
- Carry the capability through TUI thread discovery, selection, startup, and
resume flows, with a compatibility fallback for older app servers.
- Present parent-owned threads as view-only, preserve drafts and queued input,
block agent-directed commands and settings shortcuts, and keep local
navigation and inspection commands available.
## Testing
- Cover V1 writable and V2 view-only spawned threads through selection and
resume.
- Cover composer submission paths, queued and initial input preservation,
allowed navigation commands, settings shortcuts, and the view-only UI.
GitOrigin-RevId: 495ad051249e5577fb0b0c1cc8c40a0998d04918
## What changed
Give command, permissions, patch, and MCP elicitation approvals dedicated
request structs, and update TUI routing and rendering to use the wrapped
payloads.
GitOrigin-RevId: ffee4058dd27505be2a11de3758ac12bb707b6b8
## What changed
- Parse `cache_write_tokens` from response input token details and carry it through token usage aggregation.
- Expose `cache_write_input_tokens` in protocol, app-server, exec, and TypeScript SDK usage events, defaulting it to zero for compatibility with older payloads.
- Report cache-write usage in analytics, metrics, traces, and rollout data alongside existing cache-read usage.
## Testing
- Add coverage for response parsing, usage event output, aggregation, analytics, metrics, and telemetry fields.
GitOrigin-RevId: 634e4fbe3086a8923c0ee13b622573e7d9d221bd
## Why
Starting a user turn can wait on remote work. Show the submitted prompt immediately instead of leaving the input invisible during that wait.
## What changed
- Queue optimistic prompt history before app-event submissions and render a frame before starting the turn.
- Preserve the existing submit-failure behavior for direct submissions.
## Testing
- Verify that an initial prompt is added to history before its user-turn event is submitted during session replay.
GitOrigin-RevId: 57f30c6e0067127e6b082a206f7d154fcfef8d7d
## What changed
- Track connected and disconnected states across initial remote exec-server connections and reconnection attempts.
- Emit experimental `thread/environment/connected` and `thread/environment/disconnected` app-server notifications for each thread selecting the environment. Each payload identifies the thread and environment; current state is not replayed when a thread starts.
- Stop forwarding connection events when an environment selection is removed or replaced.
## Testing
- Cover connection, disconnection, reconnection, shared-environment notifications, and replacement of a selected environment.
GitOrigin-RevId: 5dd767372363c4a2a8319fc16164be117d5bd20c
## What changed
- Add experimental `beforeTurnId` support to `thread/fork` for copying history strictly before a turn, including an in-progress turn.
- Use before-turn forks for TUI backtracking and safety retries so the replacement prompt retains thread context instead of recreating the branch from the preceding turn or a new thread.
- Add experimental `deferGoalContinuation` support so safety-retry forks can inherit an active goal while waiting for the replacement turn before automatic continuation resumes.
- Hide duplicated nested-review prompts when replaying history or selecting a prompt to edit.
## Testing
- Cover before-turn truncation, fork validation, active-goal inheritance, TUI safety retries, backtracking, and nested-review replay.
GitOrigin-RevId: 4915d85ae1929a0b8c40f3ed7dca29c7a5bdcdf3
## Why
Retrying a safety-buffered turn by rolling back the active thread rewrites the
source conversation and requires the TUI to repair its local transcript state.
## What changed
- Interrupt the buffered turn, then fork after the preceding completed turn and
submit the prompt on the new thread with the faster model and low reasoning
effort.
- Start a new thread when the buffered request is the conversation's first turn.
- Preserve committed steering input in the retry, leave the source thread
intact, and restore the prompt alongside any existing draft if branching
fails.
- Do not offer the retry action for side conversations or stale and in-progress
turns.
## Testing
Added coverage for retries with prior context, first-turn retries, committed
steering input, branch failures, existing composer drafts and attachments, and
side conversations.
GitOrigin-RevId: adb49da8236e9212ef0082e033e6f715986b5cd9
## What changed
- Add an explicit restore mode for thread input snapshots and use it when replaying thread snapshots.
- Preserve the pending-steer interrupt flag alongside running-turn and queued-input state when restoring an in-flight turn.
- When in-flight state is not preserved, clear stale running flags and move pending steers ahead of already queued follow-ups while retaining their history records.
## Testing
- Expand TUI tests to cover both restoration modes, including sleep-inhibitor state, pending-steer ordering, history records, and queued submission.
GitOrigin-RevId: f4e8b2bdf065ef6c6644b7f0ea9cf32c8a9af619
## What changed
- Fork the conversation immediately before the selected prompt instead of rolling back the current thread in place, preserving the original conversation.
- Reopen the selected prompt in the new conversation with its images, text elements, and mention bindings intact.
- Start a fresh conversation when editing the first prompt, show a dedicated continuation notice, and restore the prompt with an error if branching fails.
## Testing
- Cover branching before first and later prompts, source preservation, prompt restoration, hidden review prompts, mid-turn steering, in-progress turns, stale transcript entries, and mention bindings.
GitOrigin-RevId: 15473535b3f9733b0300711a498969e6d389db79
## What changed
- Leave an output-free interrupted prompt in the transcript and open a blank
composer for the user's next instruction.
- Use the normal interruption notice for both `Esc` and `Ctrl-C` interrupts.
- Track safety-buffering prompts separately so failed retries can still restore
the prompt, including after switching between threads.
## Testing
- Cover output-free `Esc` and `Ctrl-C` interrupts, failed safety-buffer retries,
and restoration of safety-buffer state from thread snapshots.
GitOrigin-RevId: 30b368d00dfdb981d06d4c95ce3f252389b7917c
## Why
Sparse and out-of-order rate-limit updates can omit account metadata or let an
older full read overwrite a newer workspace hard stop. Credit availability also
does not always include a displayable balance.
## What changed
- Propagate the backend's `spendControlReached` state through rate-limit
snapshots and the app-server protocol, preserving it across sparse updates.
- Keep workspace hard-stop classifications for error routing and ignore stale
full-read results after a newer hard-stop notification.
- Base TUI warnings and model-switch prompts on credit availability and hard-stop
state, and show `Credits: Available` when a finite balance is hidden.
## Testing
Added coverage for spend-control mapping, snapshot merging, out-of-order reads,
workspace error routing, warning and prompt behavior, and credit status display.
GitOrigin-RevId: 18b09d493d5a620a7c079fb721ec50b38dd5b04c
## What changed
- Hide `gpt-5.4` and `gpt-5.4-mini` from model selection and direct existing users to `gpt-5.6-terra` and `gpt-5.6-luna`, respectively.
- Use Terra for memory consolidation and Luna for memory extraction and rate-limit switch prompts.
- Keep Amazon Bedrock GPT-5 catalog entries visible when their bundled model metadata is hidden.
## Testing
- Add coverage that all Amazon Bedrock GPT-5 models remain visible and update TUI expectations for the new model choices.
GitOrigin-RevId: fd69c8d5fb6b510c77204df6b7ac3f07e67cded2
## What changed
- Define `SleepItem` in `codex-extension-items` and carry `clock.sleep` events through `TurnItem::Extension`.
- Preserve sleep persistence, thread-history reconstruction, and the app-server's `type: "sleep"` schema while reusing the extension-owned type.
## Testing
- Add serialization coverage for the `clock.sleep` extension wire shape and its protocol wrapper.
- Update sleep lifecycle and thread-history tests to exercise the extension-owned item.
GitOrigin-RevId: 34bb33ed9b90a09bf4744aafdb56e019c717a168
## What changed
- Hide the working-status indicator when finalized assistant output is committed to the transcript, including single-line final answers.
- Restore the indicator when image generation begins during a running task after its streamed preamble has been flushed.
## Testing
- Add snapshot coverage for a single-line final answer and for image generation following a single-line preamble.
GitOrigin-RevId: e294a11cda3f0ce46f2bbed1be2a1380c9c73085
## Why
Full access significantly increases the risk of data loss, leaks, or unexpected behavior, so users should explicitly confirm each time they select it.
## What changed
- Always open the full access confirmation when user-reviewed approvals are active, regardless of `notices.hide_full_access_warning`.
- Remove the persistent "don't ask again" option and its acknowledgement events.
## Testing
- Update the TUI permission tests and confirmation popup snapshot to cover repeated confirmation.
GitOrigin-RevId: 0ee827332441e13d9445349ed6a5a92dc8fef4b2
## Why
Clients that account for individual upstream Responses API calls need the exact
usage for each completion rather than accumulated or estimated thread usage.
## What changed
- Add the opt-in `rawResponse/completed` app-server notification with the
`threadId`, `turnId`, `responseId`, and upstream `usage` payload.
- Emit the transient event for normal turns and compaction requests when
`experimentalRawEvents` is enabled. The event is not persisted or replayed,
and `usage` is `null` when the upstream response omits it.
- Export the notification in the app-server schemas and document its behavior.
## Testing
- Cover exact token breakdowns for turn and compaction completions.
GitOrigin-RevId: 49040a060bf1784c1ff1dd62112efb4a778428c4
## What changed
- Include the active Codex Apps tools cache and connector directory cache, when available, in diagnostic uploads that include logs.
- Resolve cache paths from the current authentication context and use stable attachment filenames.
- List both optional cache files in the upload consent dialog.
## Testing
- Add coverage for selecting existing active cache files, including a directory cache without an account ID.
- Update consent dialog snapshots to include the optional attachments.
GitOrigin-RevId: 1d4ffbf2bcb96653f03dc25f91d80dd65038d585
## Why
Model overrides for `spawn_agent` must be compatible with the multi-agent backend used by the current turn.
## What changed
- Carry each model's multi-agent backend metadata into `ModelPreset`.
- Filter the advertised `spawn_agent` model overrides for multi-agent v2 and reject overrides assigned to another backend.
- Limit error suggestions to picker-visible, backend-compatible models.
## Testing
Added coverage for hiding incompatible models from the tool description and rejecting them during spawn validation.
GitOrigin-RevId: 22c12aba67df46e9743a74f019b72a1b8b76b308
## Why
`Max` and `Ultra` consume usage limits faster than standard reasoning levels, so they should not be selected accidentally while navigating the normal effort scale.
## What changed
- Move `Max` and `Ultra` behind a `More reasoning…` entry with a dedicated warning and descriptions.
- Keep the reasoning shortcuts from silently increasing into advanced efforts.
- Apply `Ultra` to the active conversation without changing defaults for new threads, while preserving it across mode switches and thread resumes.
- Record applied thread settings in thread metadata, including explicit clearing of reasoning effort, so resumed threads restore their latest model settings unless the user supplied an override.
## Testing
- Add TUI coverage for the advanced picker, shortcuts, Plan mode, configuration defaults, and resumed conversations.
- Add app-server and thread-store coverage for persisting, clearing, and restoring model and reasoning settings.
GitOrigin-RevId: 6708c7c2e8d38f491bf63000ea34f83476afdfe6
## What changed
- Look for the Unix IDE context socket at `CODEX_HOME/ipc/ipc.sock` first.
- Fall back to the existing per-user temp-directory socket paths, including both legacy paths for UID 0.
- Apply one request deadline across all connection attempts, and stop fallback after a timeout or a protocol error on a connected socket.
## Testing
- Added coverage for socket path selection, primary preference, legacy fallbacks, and timeout and protocol-error behavior.
GitOrigin-RevId: 560c827ad3d446a82ec503779995757096ac33e0
## What changed
- Rename `Keep waiting` to `Dismiss and keep waiting`.
- Explain that no action is required, waiting continues, and the menu closes when the response is ready.
- Replace the generic confirmation hint with the new explanatory footer.
## Testing
- Update snapshots for safety-buffering prompts with and without the retry option.
GitOrigin-RevId: 2d336c59066e2689f291c5098ecc300921f39977
## What changed
- Add optional `scheduledTasks` metadata to `plugin/read` responses for remote
plugins, including hourly, daily, weekday, and weekly schedules.
- Preserve the distinction between unavailable metadata (`null`) and a catalog
response containing no scheduled tasks (`[]`). Local plugin details return
`null`.
- Export the corresponding Rust, JSON Schema, and TypeScript protocol types.
## Testing
- Cover scheduled-task deserialization and propagation through `plugin/read`.
- Verify missing and empty remote metadata remain distinct.
GitOrigin-RevId: 7af223ed0a1bf6d8f054293084a73f34c6d0332d
## What changed
- Emit `responsesapi.websocket_timing` payloads as opt-in trace events with request context, while excluding them from diagnostic uploads and persisted logs by default.
- Preserve fractional-millisecond TBT values in telemetry histograms and runtime summaries, rounding only when formatting the TUI label.
## Testing
- Cover timing-log filtering, fractional TBT collection and display, and existing whole-millisecond duration behavior.
GitOrigin-RevId: 5f0a1c60c237abed17cc8b2d569ca77fbbc6ec41
## What changed
- Build a reasoning payload for every Responses request and always include `reasoning.encrypted_content`.
- Remove `supports_reasoning_summaries` from model metadata and retire the `model_supports_reasoning_summaries` configuration override.
- Use configured or model-default reasoning effort without a capability gate, including for guardian reviews and tracing.
GitOrigin-RevId: 2c9f194a5d2d4d688a2235299e6358f82ab8e1ea
## Summary
The safety-buffering message currently leads with additional safety
checks, which can make the delay feel accusatory. Update it to describe
the system taking more time before responding, matching the revised
user-facing language.
- Replace the safety-buffering copy in both retry and non-retry flows.
- Keep the faster-model escape hatch while aligning its wording with the
updated message.
- Update the TUI snapshots for both states.
## Why
Reasoning summaries can contain an empty HTML comment placeholder, `<!--
-->`, when a generated summary part has no prose. The TUI treated that
placeholder as visible summary content, so it leaked into both the
completed conversation history and persisted transcript. Multi-part
empty summaries could also leave later generated status headings visible
as orphaned transcript content.
## What
- Strip the empty reasoning-summary placeholder at the shared
`ReasoningSummaryCell` boundary.
- Suppress the cell when removing placeholders leaves only generated
bold status headings.
- Cover the multi-part placeholder-only shape with a rendering
regression test for both normal history and transcript output.
## How to Test
1. Start Codex TUI with reasoning summaries visible, for example with
`hide_agent_reasoning = false` and `model_reasoning_summary =
"detailed"`.
2. Run a turn that receives an empty generated reasoning-summary part.
3. Confirm that the in-progress status heading may appear while the turn
is running, but the completed history and transcript contain neither
literal `<!-- -->` tokens nor orphaned reasoning headings.
4. Confirm that a reasoning summary with actual prose still renders
normally.
The model output is nondeterministic, so the targeted regression covers
the exact multi-part placeholder shape from the report:
- `just test -p codex-tui
reasoning_summary_block_hides_empty_html_comment_parts`
## Why
Ultra reasoning may proactively use multiple agents. When
`features.multi_agent_v2.max_concurrent_threads_per_session` is
configured at 8 or higher, explicitly selecting Ultra can allow up to `N
- 1` subagents to work concurrently and increase usage quickly. Showing
the configured limits at selection time makes that tradeoff visible and
points users to the setting that controls it.
## What changed
- Show a warning history cell after the user explicitly selects Ultra
reasoning with a concurrent-thread limit of at least 8.
- Include the configured concurrent-thread count and maximum subagent
count in the warning.
- Apply the warning consistently across model and reasoning pickers,
Plan-mode scope selection, and reasoning shortcuts.
- Keep the trigger limited to the selected reasoning effort and
configured thread limit, independent of how multi-agent v2 is activated.
- Add focused threshold coverage and an `insta` snapshot for the
rendered warning.
## User impact
Users with high multi-agent concurrency receive a concrete warning
immediately after selecting Ultra. Other reasoning efforts, limits below
8, and startup behavior are unchanged.
https://github.com/user-attachments/assets/5795bcb9-432e-42bc-bde3-ee363e9aeb69
## Test plan
- `just test -p codex-tui ultra_reasoning_selection`
- Built the full debug CLI with `cargo build -p codex-cli`.
- Manually verified the debug TUI with a 10-thread limit: switching from
Max to Ultra displayed the warning with 10 concurrent threads and up to
9 subagents.
## Description
This PR migrates standalone web search onto the extension-owned
turn-item path introduced in #31283.
Standalone web search now emits `ExtensionItem::WebSearch` through
generic `TurnItem::Extension`, while app-server still exposes the
existing typed `ThreadItem::WebSearch` JSON shape. Hosted Responses API
web search stays on core-owned `TurnItem::WebSearch`.
## What changed
- Added `web_search::WebSearchItem` and `WebSearchAction` to
`codex-extension-items` under the stable `web.search` kind.
- Collapsed `ExtensionTurnItem` to generic `{ item, legacy_events }` now
that no typed extension special cases remain.
- Kept the existing `WebSearchBegin` / `WebSearchEnd` compatibility
events and canonical-first ordering.
- Updated app-server projection/history and generated TypeScript; the
app-server JSON schema is unchanged.
## Description
This PR adds a `codex-extension-items` crate for extension-owned
`TurnItem` schemas, and updates standalone image generation to start
using it via `TurnItem::Extension`.
This gives us a way to prevent Core from having to be aware of all
extension items. App-server still exposes the existing public
`ThreadItem::ImageGeneration` shape, now by wrapping the same shared
`image_generation::ImageGenerationItem` type.
The new `codex-extension-items` crate is necessary because the image gen
extension item is used by:
- `codex-image-generation-extension`, which produces it.
- `codex-tools / core`, which carry it generically.
- `codex-protocol`, which serializes it into lifecycle events and
rollouts.
- `app-server protocol`, which wraps it in public
`ThreadItem::ImageGeneration`
```
extension implementation
↓
codex-extension-items
↓
protocol / tools / app-server
```
We keep the hosted Responses API image generation as
`TurnItem::ImageGeneration` because core still owns its persistence and
legacy fanout.
### Before
Standalone image generation is implemented as an extension, but its item
representation previously lived in the core protocol. This sets the
precedent that core is aware of all extension items, which would be good
to avoid.
```
image-gen extension
→ constructs codex_protocol::ImageGenerationItem
→ emits ExtensionTurnItem::ImageGeneration
→ core matches ImageGeneration specially
→ protocol stores TurnItem::ImageGeneration
```
### After
```
image-gen extension
→ constructs extension-owned ImageGenerationItem
→ emits generic ExtensionItem
→ core transports/persists it generically
→ app-server wraps ImageGenerationItem as ThreadItem::ImageGeneration
```
Future extension items can have typed app-server APIs without adding a
new `TurnItem` variant, `ExtensionTurnItem` variant, or core emitter
match arm.
## What changed
- Added `codex-extension-items` with the closed `ExtensionItem` enum and
shared `image_generation::ImageGenerationItem` schema.
- Added generic `TurnItem::Extension(ExtensionItem)` and
`ExtensionTurnItem::Extension { item, legacy_events }` paths.
- Updated standalone image generation to emit a typed extension item and
provide its existing legacy `ImageGenerationBegin` /
`ImageGenerationEnd` events explicitly.
- Kept canonical lifecycle ordering: core emits `ItemStarted` /
`ItemCompleted` before extension-provided legacy events.
## Follow-up
Standalone web search still uses its typed special-case path. Migrating
it later would let `ExtensionTurnItem` collapse into a single
extension-item struct.
## Summary
- Treat streamed Responses `bio_policy` failures as terminal invalid
requests instead of retryable stream errors.
- Recognize the new biology policy code and message in the TUI while
preserving the legacy `invalid_prompt` contract.
- Keep the existing dedicated biology safety notice and add
regression/snapshot coverage for all supported error shapes.
## Why
[openai/openai#1068559](https://github.com/openai/openai/pull/1068559)
gates a Responses API contract change from `invalid_prompt` and the
legacy message to `bio_policy` and new biology copy.
Without this compatibility change, streamed blocks are retried as
transient failures and the OSS TUI falls back to a generic/raw error
instead of the dedicated safety notice.
## Validation
- `just test -p codex-api` — 137 passed
- `just test -p codex-tui
app_server_safety_access_errors_render_dedicated_notice` — passed
- `just fix -p codex-api`
- `just fix -p codex-tui`
- `just fmt`
- `just test -p codex-tui` — 2,957 passed; two reproducible failures
remain in untouched Guardian feature-flag persistence tests:
-
`update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
-
`update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
## Why
Users can see that usage-limit reset credits are available, but not
which credits they have, when each one expires, or which credit will be
consumed. The TUI should use the supported rate-limit RPC for that
information without maintaining a second reset-credit request path.
## What changed
- load reset-credit details through the existing
`account/rateLimits/read` refresh when the user opens **Redeem usage
limit reset**
- show available credits sorted by expiry, using the backend title when
present and a scope-based fallback otherwise
- consume the exact selected credit and preserve its idempotency key
across retries
- fall back to the existing generic reset action when the RPC returns a
positive count without detail rows
- remove the dedicated list-RPC event, request, response-combining, and
TUI state plumbing
- handle a selected credit becoming unavailable without incorrectly
caching the user's total count as zero
- handle forward-compatible unknown reset types with the existing
scope-based fallback label
## TUI preview
Rendered from the final standard-width and narrow `insta` snapshots in
this PR.
<img width="1280" height="570" alt="pr30488-reset-picker-preview"
src="https://github.com/user-attachments/assets/8b84cd33-cb35-4a37-aaed-dbd6b62bff51"
/>
## Validation
- `just test -p codex-tui chatwidget::tests::usage` (32 passed)
- `just fix -p codex-tui`
- no pending `insta` snapshots
Uses the reset-credit details added by #30395.
Fixes#29618.