## What changed
Add `CodexThread::reproject_mcp_on_next_turn()` to request an MCP reprojection after `TurnStarted` and before tools are bound. Repeated requests coalesce, and idle reconciliation or prewarming leaves the request pending until the next regular turn.
## Testing
Add coverage for deferred requests surviving prewarm and idle reconciliation, coalescing into one reprojection, and exposing refreshed tools in the turn's first model request. Verify that discovery starts after `TurnStarted`.
GitOrigin-RevId: 260b2381013291a47eb9a7f736c129de76c5897f
## Why
Trusted classifier evidence needs to fit configured entry limits while preserving complete records and metadata that reflects only delivered reviews.
## What changed
Apply elastic caps before rendering trusted tools, trusted skills, and previous reviews into developer messages. Omit oversized tool attestations and review fragments whole, retain only complete skill paths that fit, and record omissions for the request's omission notice. Keep review IDs aligned with retained fragments and preserve fixed-budget behavior.
## Testing
Add coverage for whole-record omissions, retained review IDs, and omission notices. Exercise orchestrator connector evidence with both fixed budgeting and an elastic tool entry cap.
GitOrigin-RevId: 729db452026f93b59765a3936730b9b6dddfcf9a
## What changed
- Add `async_elastic_budgeting` and `async_elastic_sections` under `[features.guardianv2]`, independently of synchronous budgeting and disabled by default.
- Apply section limits and elastic allocation to new classifier evidence after accounting for setup and retained conversation history. Preserve the configured elastic policy when applying model defaults.
- Keep permission context whole during elastic allocation and record truncation observations when image preparation rejects an image.
## Testing
Add coverage for configuration validation, fixed and elastic conversation budgeting, retained history and cursor preservation, and complete classifier requests that retain evidence beyond the fixed entry limit.
GitOrigin-RevId: 2955f0482f7c3e18325e296fc2ccb6592ffcb73a
## What changed
Allow `thread/inject_items` to accept wrapped items with `retention: "default"` or `retention: "always"`, while preserving support for raw response items. Persist explicit policies separately from legacy client-authored metadata.
Carry explicitly retained items through local and remote compaction, context-window changes, and child-agent creation, subject to retention budgets. Preserve history order and keep retained tool exchanges together; require matching calls and outputs to be adjacent in the injection request and both marked `always`.
Update Quinn dependencies and record exceptions for additional Hickory DNSSEC advisories where DNSSEC is disabled.
## Testing
Update injection tests for explicit retention metadata and extend the compaction scenario to cover a retained tool exchange across repeated compaction and restart.
GitOrigin-RevId: 1195a4ed62dc162a62e58bc2ad733262fbabea27
## What changed
- Read response window metadata through `current_window_from_state` with an explicit session state lock, releasing it before assembling response metadata.
- Name the token budget feature check used when restoring a forked child window.
- Pass an explicit `TestEnv` into the async compaction test helper and build with `build_with_environment`.
GitOrigin-RevId: 7ad852dbd65689e814f62cad645330ac5dac80f4
## Why
An unset voice preference should use the call destination's default. Changed or cleared preferences should also take effect on the next V3 call, even when the thread retains an older setting.
## What changed
- Use `gpt-live-1.1-codex` as the default V3 realtime model.
- Preserve an unset voice until request serialization, defaulting V3 API calls to `marin` and ChatGPT calls to `cove`, while honoring explicit voice selections.
- Reload current voice settings when starting a new V3 call through the app server, including cleared preferences.
- Populate the TUI voice picker from the V3 catalog, add `marin` to that catalog, and remove voice-catalog lookups from call startup and preference saving.
## Testing
Add regression coverage for API and ChatGPT voice defaults, explicit overrides, changed and cleared settings, and TUI call requests and voice selection.
GitOrigin-RevId: d0dd4dcd4bcad9ab869d7bf524e7095a88ffcfaa
## Why
MCP servers registered under the same name in different environments need distinct inventory, routing, and status reporting.
## What changed
- Keep MCP inventory and runtime status keyed by registration scope so same-named servers remain separate.
- Add optional `environmentId` selectors for status lookup, tool calls, resource reads, and OAuth login. Omitting the selector preserves existing name-only routing.
- Carry environment identity through startup notifications, elicitation requests, and tool-call history, and display it in the TUI.
- Support `/mcp login <name> --environment <id>` and update generated protocol schemas and SDK types.
## Testing
Add integration coverage for two environments with identically named MCP servers, tools, and resource URIs. Verify separate inventory, explicit environment routing, legacy routing when the selector is omitted, and errors for unknown environments. Update protocol and TUI tests for environment identity.
GitOrigin-RevId: 074a3db10549438cb6aff33eb7bed10791adae4d
## Why
Recording inference starts synchronously serializes prompts and writes trace payloads before model work can proceed. Defer that work so inference dispatch can continue while the trace is recorded.
## What changed
- Use one worker per trace bundle to write events in submission order, with up to eight pending jobs.
- Share prepared prompts and encoded requests with the worker, and build remote compaction snapshots there. Write payloads before publishing events that reference them.
- Add `TraceWriter::flush` and `ThreadTraceContext::flush` for live reads. Drain accepted jobs and seal the bundle on shutdown; suppress the closing marker after a recording failure.
## Testing
Add tests for deferred prompt serialization, ordered start and completion events, shutdown draining, and serialization failures that preserve earlier evidence without publishing a closing marker. Verify compaction snapshots are built on the worker and skipped when tracing is disabled.
GitOrigin-RevId: 32fd787bb1d281f1814df2f08c73b667628f8add
## What changed
- Replace individual JSON payload files with numbered Zstandard shards in trace schema v3. Add `PayloadReader` to resolve payload references, cache decoded shards, and validate payloads during replay.
- Capture exact outgoing HTTP bodies and WebSocket messages alongside prepared prompts. Preserve full formatted context for continuations from unrecorded WebSocket warmups while retaining the actual incremental request.
- Flush payload records before publishing references and seal the final shard before recording completion. Replace `recording_complete` with `recording_status` to distinguish unclosed recordings, closed recordings with partial payloads, and complete recordings.
Reduce trace bundles with the binary that recorded them.
## Testing
Add coverage for shard rotation, oversized records, live reads, cache eviction, and malformed or corrupt payloads. Extend HTTP and WebSocket integration assertions to verify captured requests and prepared prompts, including warmup continuations.
GitOrigin-RevId: 40ce3c11383f48e08f52e7120b706c61a449df9c
## What changed
- Add the disabled-by-default `catalog_apps_instructions` feature to use the selected model's `model_messages.apps.usage_instructions`, subject to existing Apps availability and model gates.
- Preserve valid catalog text literally, allow an empty string to clear guidance, and fall back to bundled instructions for missing, whitespace-only, or oversized values. Overrides are limited to 800 UTF-8 bytes.
- Reconcile guidance with the latest retained Apps fragment, emitting replacement or removal notices when needed and avoiding repeated updates across resumes. Preserve compatibility with bundled guidance and legacy checkpoints.
- Recognize catalog Apps fragments as contextual developer messages in event mapping and rollout rollback.
## Testing
Add resolver, world-state, client, and scenario coverage for literal text and byte limits, feature and availability gates, model switches, clearing guidance, resumes, and legacy history recovery.
GitOrigin-RevId: 6240d407ada8f22fa101753ff3ddb338632ae283
## What changed
- Update the workspace, Bazel toolchain and lockfile, CI and release workflows, and Windows setup script from Rust `1.95.0` to `1.99.1`.
- Adapt Rust code to the updated toolchain and Clippy lints, including `try_update` for atomics, `as_chunks` for fixed-size slices, and targeted allowances for generated tonic services.
- Refresh the halfwidth sound mark rendering snapshot to use literal characters in debug output.
GitOrigin-RevId: 5852029f687436dc814c2bca68141ee1f4a67d49
## Why
Suspending a locally controlled agent tree must preserve unfinished turns and child results that arrive during teardown so they remain available after recovery.
## What changed
- Add `ThreadManager::suspend_agent_tree` to stop durable trees, close their writers, and return unfinished root and named V2 child turn IDs plus any pending root wake.
- Persist terminal child results before suspension succeeds, including results queued for evicted parents. Report failed or unconfirmed writes.
- Add `load_suspended_agent` to restore named V2 descendants through their recorded ancestors without starting model turns.
- Allow empty `continue_turn_if_idle` input to wake on saved results, guarded by the preceding turn ID. Keep mail queued until task registration so suspension can preserve it.
## Testing
Add coverage for completion and wake races, child errors, parent writer failures, evicted parents, descendant restoration, repeated suspension after caller cancellation, and ephemeral roots remaining active.
GitOrigin-RevId: 3041791f51bff2555210f6b2d2443f9f05f68330
Describe remote board connection settings, host ownership, and configured
clocks in general terms. Update the remote board test credential to match
that terminology.
GitOrigin-RevId: c2c32808c98afad849f6e4f59f75d8d204f51694
## What changed
Stop rebuilding permission profiles through the legacy sandbox policy when only the working directory changes. Preserve the profile, its active selection, and profile workspace roots while updating runtime workspace roots for the new directory.
## Testing
Extend regression coverage to check that directory-only updates preserve the permission profile snapshot and expected thread settings. Verify that workspace-write permissions allow ordinary files in the new workspace while denying writes to `.git/config` and the previous workspace.
GitOrigin-RevId: a4f4b2dc4ffa16cbf33ddb124eed4b759b2aae78
## Why
Plan items used a single ID derived from the turn ID, so multiple completed plans within one turn shared an ID across retries or tool continuations.
## What changed
Generate UUIDv7 plan item IDs and carry an unfinished plan's ID across model requests within a turn. Once a plan completes, assign a fresh ID to the next plan.
## Testing
Add unit and integration coverage for unfinished retries, retries after plan completion, and tool continuations, including matching streamed events to saved completions. Update the app-server test to check plan IDs against the start notification.
GitOrigin-RevId: 87b4b3e6bd74224ea96f4308f739bcd2efb62299
## What changed
Preserve original root conversation evidence, retained instructions, assistant context, and verified answers until request preparation. Apply shared section preparation to both synchronous and asynchronous reviews, preserving fixed limits and omission notices while allowing elastic preparation to use the originals. Cache the fixed root view for reuse.
Split classifier setup from final input assembly and normalize new images before deduplication and token accounting, preserving committed history.
## Testing
Extend tests for fixed and elastic preparation across both review profiles, original root evidence after handoff, and image normalization during retained-request preparation.
GitOrigin-RevId: 86c83384c1f5be3707622d675fc54b4c8e1ddc0a
## What changed
Route direct reviews through the reusable Guardian session so sequential `thread/guardianReview` calls on the same loaded thread can share review history with live approvals. Keep the reviewer conversation separate from the actor and follow the parent thread's persistence settings. Retries reassess the final call under the current policy.
## Testing
Extend app-server coverage to verify history reuse within a parent thread and isolation between parents. Extend the core scenario and snapshot to cover sequential direct reviews without executing the recorded commands.
GitOrigin-RevId: 5f10a04aec43a9351e38575265cb6b5ff06530a5
## What changed
- Remove `Config::set_legacy_sandbox_policy` and update session, approval, and Guardian test setup to set permission profiles and workspace roots explicitly.
- Reuse `PermissionProfile::from_legacy_sandbox_policy_for_cwd` for legacy policy validation and updates in `Permissions`.
GitOrigin-RevId: 5ee92c46290ee6a3d7e2d2db7b02641e80bdc44f
## Why
Allow collector credentials to refresh without rebuilding OpenTelemetry providers.
## What changed
Add `otel.headers_helper`, a command run from `CODEX_HOME` that returns a JSON object of header strings. Share its results across explicitly configured HTTP log, trace, and metric exporters. Refresh every 29 minutes by default, configurable through `otel.headers_helper_refresh_interval_ms`.
Helper headers override matching static headers. Failed refreshes block affected exports until the helper recovers, and HTTP redirects are disabled when helper headers are used. Repository-local configuration cannot set the helper; exporters set by admin requirements, gRPC exporters, and built-in analytics do not use it. Helper execution respects network policy.
## Testing
Add tests for shared execution, credential refresh and recovery, blocked exports after failure, network restrictions, and configuration validation. Collector tests cover header precedence across all three signals using JSON and binary HTTP encodings, including exclusion of an admin-managed exporter.
GitOrigin-RevId: 89018ac09c2c99523d3f92bf77048e7ed9dae5f2
## What changed
Parse reasoning removals from response `input_transformations` and carry the counts through completion events to sampling telemetry.
- Add `codex.responses.reasoning_replay` to distinguish unavailable reports, no reported removals, prefix mismatches, and other removals.
- Add `codex.responses.reasoning_items_removed` histograms by bounded removal reason, grouping unknown or missing reasons under `other`.
- Include zero counts for usable reports; exclude missing, null, or malformed reports from histograms without failing the response.
- Use the sampling step's session telemetry when recording response events.
## Testing
Add SSE and WebSocket integration coverage for report availability, removal counts, unknown reasons, zero observations, and `product_sku` tags in exported metrics.
GitOrigin-RevId: 83c70ca6067fa4b34bf5c463958b4632a7a0a188
## What changed
- Initialize item and context-window ID generators per thread, reuse the stored window on resume, and give history reconstruction a separate item generator.
- Recover item ordinals from checkpoint replacement history, guardian history, and retained context without lowering the cursor established by earlier records.
- Stamp compaction resume metadata with the next item ordinal in append order, tracking the cursor in local and in-memory thread stores.
## Testing
Extend the history ordinal test to verify that a checkpoint records the cursor at its position in a batch, excluding later allocations.
GitOrigin-RevId: 7121b747a039dc5477235078702137d1ff74e789
## What changed
Add `transcript_selected_exec_results` to synchronous Guardian elastic budgeting so selected Code Mode `exec` outputs can receive a separate token reservation and entry cap from ordinary tool evidence.
Configure selection with `nested_tool_names`. Match results against the host-recorded inventory of completed nested tool calls, including normalized tool names, even when the original `exec` call has left review history. Leave the new section's reservation at zero when omitted.
## Testing
Add coverage for recorded-inventory matching and results whose calls are missing from history. Extend the elastic budgeting scenario to verify that selected output is retained while ordinary tool output is capped.
GitOrigin-RevId: 6a8de250e36b18f2acfdab993c83c254f101ce87
## Why
MCP servers discovered on different executors can share a name. Resolving them by name alone exposes only one server and prevents tools and resources from being addressed independently.
## What changed
- Add the disabled-by-default `multi_environment_mcp` feature to expose environment-scoped servers, including multiple installations of the same plugin.
- Carry exact `McpServerKey` identities through catalogs, connections, tool calls, resources, and approval tracking. Give environment-scoped tools stable namespaces derived from their environment.
- Include `environment_id` in scoped resource listings and accept it in resource requests. Require it for environment-owned servers when multiple environments are selected.
- Preserve server ownership through hooks and use the owning environment's permissions for scoped elicitation review.
## Testing
Add coverage for same-named servers across environments, independent calls and approvals, resource selection, plugin discovery, and rejection of hook changes to the tool environment.
GitOrigin-RevId: 5593372b06a15c16aa3220faa3b19f5d3b20e67e
## What changed
- Replace free-form `AgentMessageDisplay` actions with a version `1` contract using `show`, `hide`, and `block` modes, with typed annotations, replacements, block reasons, and trusted-contact handling.
- Discard invalid or unsupported display instructions and set `moderated` to `true` when reading moderation data in Rust and the Python SDK.
- Update generated JSON schemas, TypeScript types, and Python SDK models to match the contract.
## Testing
Add coverage for display variants, tolerance of extra fields, and unsupported-version or unknown-mode fallback. Update the final-answer moderation test and add Python coverage for thread history and item notifications.
GitOrigin-RevId: ec64070002da67e8e377dccb3728806ac8b290e7
## What changed
- Add the stable `incremental_tools_legacy_gcp` feature, enabled by default, to control incremental tool declarations on regular GCP Responses independently of Amazon Bedrock.
- Mark `incremental_tools_legacy` stable and keep it disabled by default for Amazon Bedrock.
- Expose the new flag in the configuration schema.
## Testing
Update integration coverage for GCP defaults and opt-out, independent provider flags, and incremental tool declarations during remote compaction.
GitOrigin-RevId: 7acf085789d44122fd2a5da97932a8b9e93e240e
## Why
Requests that exceed the server's advertised WebSocket message size limit can fall back to HTTP without first uploading the oversized message.
## What changed
Read `x-codex-websocket-max-message-bytes` from the handshake response and check the serialized request's byte length before sending. Route oversized requests through the existing HTTP fallback. Ignore missing or invalid limits, and remove the close-code-specific wording from the size-limit error.
## Testing
Add a fallback test that advertises a one-byte limit and verifies zero WebSocket generation requests and one HTTP request.
GitOrigin-RevId: 03b42012ca77d6b046e937fef8e6335d855a1c10
## Why
A WebSocket close with code `1009` before any text arrives indicates that the request exceeds the peer's message size limit. Retrying the request over another WebSocket does not address that limit.
## What changed
- Classify these early size rejections as requiring HTTP fallback and switch transports without exhausting WebSocket retries, including during prewarming.
- Preserve ordinary stream retry behavior for size closes after any text frame and for other close codes.
## Testing
Add integration coverage for early size rejections during generation and prewarming, size closes after metadata, rate limits, or response creation, and ordinary closes.
GitOrigin-RevId: 4550d289bb414fec1faae2a195bcc635d394117b
## Why
A subagent can use a different model from its parent, with different supported access programs. Saved Daybreak choices need to resolve against the subagent's model and remain consistent throughout its turn, including compaction.
## What changed
- Resolve saved choices before native subagent turns start, preserving explicit turn overrides and applying saved toggles on later turns.
- Distinguish inherited parent programs from explicit child selections. Adapt inherited Daybreak Blue/Red selections to the child model while retaining the saved choice as the default for later turns and nested subagents.
- Validate the account associated with automatic selections and reject incompatible saved choices before sending model requests, while retaining rejected user input in conversation history.
- Require model changes to wait until the next turn when a saved Daybreak choice is present.
## Testing
Add coverage for both multi-agent spawn versions, model-specific selection, automatic compaction, WebSocket response reuse, account changes, unsupported choices, and rejected-input persistence across resume.
GitOrigin-RevId: 11971138d656600d9878187225e4d33217e68ad4
## What changed
Carry `ContextWindowId` through session metadata, compaction checkpoints, rollout recording, and thread creation instead of converting IDs to strings. Add deserialization and JSON schema support while preserving the serialized string format and legacy numeric compaction IDs.
Validate deserialized IDs as UUIDv7 values before restoring context windows, preserving the existing handling of unsupported IDs.
GitOrigin-RevId: fda329d0654f438171a955c9f75550817c32c047
## Why
Converting message content to tool output previously reduced file-backed audio to a text file ID, losing its audio type.
## What changed
- Allow `input_audio` tool output items to carry either `audio_url` or `file_id`, preserving both forms during content conversion.
- Account for file-backed tool audio in history estimates and output truncation, and prepare only inline audio data.
- Reject uploaded audio in raw function and custom tool output injection, extending the existing requirement to submit uploaded audio through typed turn input.
- Regenerate app-server schemas and TypeScript/Python types while preserving the Python inline audio class name.
## Testing
Add coverage for tool audio wire-format round trips, repeated file audio sharing text and audio output budgets, and rejection of raw uploaded audio injection across messages and tool outputs. Extend Python SDK coverage for the inline tool audio shape.
GitOrigin-RevId: f4704466e6151662d2c8b8dc3f5ca2ab2f5710a2
## Why
MCP config refreshes previously retained session app overrides, leaving connector approval changes unapplied in existing sessions.
## What changed
- Refresh explicit session `apps` overrides alongside `plugins`, allowing updated link approval settings to take effect on the next turn.
- Preserve overrides for omitted sections and restore inheritance when a section is an empty table.
- Validate app overrides and the effective app configuration, rejecting refreshes that expose invalid inherited settings.
## Testing
Add coverage for independent and combined app/plugin updates, clearing overrides, and rejecting invalid inherited app settings. Add an integration test verifying that changing a link's approval mode from `approve` to `prompt` requests approval before executing the next turn's tool call.
GitOrigin-RevId: 3fa36744a9ccd9e735e4cda7f061ccff1cf2a269
## Why
Background plugin cache refreshes fetched recommendations even when plugin recommendations were disabled.
## What changed
Pass the effective recommendation feature state into `PluginsConfigInput` and skip recommendation cache warming unless apps, plugins, and either `tool_suggest` or `recommended_plugins` are enabled. Installed-plugin cache refreshes continue independently.
Disable `tool_suggest` and `recommended_plugins` by default in core and app-server test helpers, with explicit overrides for recommendation tests.
## Testing
Update cache-warming and external-login recommendation tests to opt in explicitly. Update config RPC assertions to verify the test helpers' session flag overrides.
GitOrigin-RevId: dc04e2847c94e2b15842fcd95cc0cf1f104e1fac
## Why
Code Mode needs a way to forward mixed MCP tool results while preserving their content types and order.
## What changed
Add `content(block)` and `content(iterable)` so callers can forward tool output with `content(result.content)`. Text, image, and audio blocks become their corresponding output items; resource links and embedded resources are serialized as text. Invalid blocks and encrypted text are rejected, and iterators are closed when a block is rejected.
Share MCP block conversion and image detail types with the protocol layer, while preserving existing `image()` and `audio()` input handling.
## Testing
Add coverage for mixed content ordering, iterator behavior and cleanup, invalid blocks, image metadata, short audio clips, and output suppression after exit. Add an integration scenario verifying that MCP text and image blocks reach the model in order.
GitOrigin-RevId: 83832ec6c530dd35ea1e3373680627997c6e13c1
## Why
When a workspace has an unreadable ancestor, PowerShell can start with `$PWD` unset and its filesystem drive at the root, breaking relative paths.
## What changed
Prefix PowerShell commands in the MXC sandbox with a guarded workaround that restores the location from the process working directory when `$PWD` is unset. Preserve locations already initialized by startup or a profile.
## Testing
Extend the MXC PowerShell integration test to cover an unreadable ancestor, checking that `$PWD` matches the process working directory, relative file access works, and the parent and sibling file remain inaccessible.
GitOrigin-RevId: 4fb067db52a7f3c6e819169016fe6bd104a277a1
## Why
User-configured model catalogs can supply Guardian prompt templates that omit policy slots or add conflicting instructions. Managed rules need a trusted template to reach the reviewer.
## What changed
- Use the bundled Guardian policy template when managed policy or additional rules are present, while preserving explicit host-provided templates.
- Remove `auto_review.extra_policy` and `auto_review.experimental_policy_template` from configuration and the schema. Warn when they are used, directing additional rules to `guardian_extra_policy` in managed `requirements.toml`.
## Testing
Add regression coverage for managed rules with user-supplied catalog templates, explicit host templates, and migration warnings for the removed settings.
GitOrigin-RevId: 7f00bfaa85051272ed70ceb2fcb64ffc297b8755
## Why
Waiting for host acceptance of a service-tier update in the submission loop can block interrupts while the host receipt is pending.
## What changed
Move the host acceptance wait out of the submission loop while keeping explicit thread settings replies pending until acceptance completes. Report handoff failures to the caller while preserving the locally committed settings, and allow a subsequent explicit request for the same tier to retry a failed handoff.
## Testing
Add a WebSocket regression test covering interrupts with pending host receipts, failure reporting, same-tier retries, and continued thread operation after startup caller cancellation.
GitOrigin-RevId: 1b27d156eba3ebb47e717a987f41f4f595635be8
## Why
Holding the session MCP gate during `tools/list` blocks other runtime access. Releasing it requires preventing stale refresh results from publishing after configuration or authentication changes.
## What changed
- Capture the Apps client under the session gate, then release the gate before fetching tools.
- Validate runtime and authentication state before publishing the shared cache and client catalog; retry a superseded refresh once.
- Wait for in-flight Apps refreshes before capturing model tools, preparing Apps calls, or shutting down the runtime.
## Testing
Add regression coverage for stale refreshes after runtime invalidation or logout, publication validation after call preparation drains, and a model step that waits for refreshed Apps tools while MCP status queries remain available.
GitOrigin-RevId: 42d4be8c4a9218933f8e3d07fc7f32f2da9cbd9d
## Why
MCP tools marked with `readOnlyHint: true` could still require approval in automatic mode when `destructiveHint` was also true.
## What changed
Give `readOnlyHint` precedence over `destructiveHint` and `openWorldHint` when deciding whether annotations require approval. Explicit prompt mode and strict automatic review continue to require their respective approval checks.
## Testing
Update unit tests for conflicting annotations, prompt mode, and strict automatic review. Extend app integration coverage to verify that read-only calls proceed while writes prompt in both automatic and writes approval modes.
GitOrigin-RevId: 11a930b857886bf41d09fd54c3a38607ae3d1b4e
## What changed
Allow GCP Responses requests to use `incremental_tools_legacy`. When enabled, tool declarations are sent through `additional_tools` inputs instead of the top-level `tools` array.
## Testing
Extend Vertex request coverage to check incremental tool declarations, including namespaces, tool search, and `exec_command`. Add GCP cases to the scenario that verifies tool catalog updates are appended without rewriting history, with incremental tools enabled and disabled.
GitOrigin-RevId: 8f4c02f8d62575e24e695d6fae0472a09625409f
## What changed
Move `ThreadMetadataBuilder` into its own module, make its fields private, and replace direct field assignments with fluent `with_*` methods. Initialize `updated_at` and `recency_at` from the creation time and default the approval mode to `OnRequest`.
Update `apply_rollout_items` to accept a boxed `ThreadMetadata` seed, keeping callers' async frames small while preserving existing database fields except for the seed rollout path. Add `build_thread_metadata` to use the state runtime's configured provider, and use `thread_id_from_rollout_path` directly for the doctor's filename fallback.
GitOrigin-RevId: a27e4c6b22832e902922dbdd60d7f5c11b4a1a83
## Why
An explicit denial from a workspace inference hook should stop the request, including retries and compaction model fallback.
## What changed
Recognize `inference_hook_denied` provider errors and preserve the provider's message, with a fallback when none is supplied. Expose the distinct `inferenceHookDenied` error through the app-server protocol and generated schemas and SDK types. Treat the denial as non-retryable during turns, compaction, and guardian review.
## Testing
Add coverage for terminal denials over HTTP, SSE, and WebSocket, error serialization and persistence in `thread/read`, and compaction failures that preserve token usage and history without retrying or falling back to another model.
GitOrigin-RevId: 2ebd480f01e52f4e6bd3db8a0f92d5814d18ccb1
## What changed
Route MCP elicitations through the standard handling paths for Xcode 26.4 clients. Remove the client-specific auto-deny flag and the synthetic acceptance of session elicitation requests without dispatching them to the client.
Simplify `request_mcp_server_elicitation` to return the optional response directly, and remove telemetry guards that depended on whether the workaround bypassed dispatch.
GitOrigin-RevId: ab540dcd67f8fa6d16c69bc7629f436e4b5aa73a
## What changed
Mark `untrusted_as_tool_output` as stable and enable it by default. Untrusted additional context, such as browser information and goal objectives, now reaches the model as `function_call_output` items in the `agent` namespace instead of user messages. Setting `features.untrusted_as_tool_output = false` preserves the message format.
## Testing
Update core, app-server, TUI, and Python SDK test expectations for the default output format. Cover context persistence, deduplication, goal continuation, and explicit opt-out behavior.
GitOrigin-RevId: 30828351e2ed584928f6055b6dcf276d8288c0fb
## Why
HTTP 400 responses with `context_length_exceeded` need to reach context-window recovery so manual compaction can retry with less history. Streaming context-window failures should end the stream immediately.
## What changed
- Map `context_length_exceeded` through the shared terminal provider error parser for HTTP 400 responses and events without an HTTP status.
- Return SSE context-window failures immediately.
- Preserve retryable handling for WebSocket errors carrying HTTP 503, even when their code is `context_length_exceeded`.
## Testing
Add coverage for WebSocket status handling and immediate SSE termination with retry headers. Update the manual compaction test to verify recovery from an HTTP 400 context-window error by dropping one history item and retrying.
GitOrigin-RevId: 56d8c831c2fad2ca1318318a3b4258fcc516d689
## Why
A `403` with `codex_workspace_access_denied` indicates that the account cannot use Codex in the selected workspace. Retrying or falling back to HTTP does not resolve that denial.
## What changed
Map `codex_workspace_access_denied` and `invalid_workspace_selected` responses to a shared workspace access denial error, and rename the error variant to reflect its broader scope. Keep workspace denials excluded from compaction model fallback.
## Testing
Extend API error mapping tests to cover the new code on `403` and preserve ordinary handling for `503`. Add WebSocket coverage verifying that an explicit workspace access denial does not trigger HTTP fallback.
GitOrigin-RevId: e601a22a0fa783a4ce5401a98ff9c8d3d9d1b074
## What changed
Recognize `content_policy_violation` in HTTP 400 responses and streamed errors as a dedicated, non-retryable error. Preserve the provider's message and available HTTP status, use a fallback message when needed, and report `CodexErrorInfo::InvalidPrompt` to clients.
End the response stream immediately on this error and stop compaction from falling back to the current model after a content policy rejection. Add redacted diagnostic output and a dedicated sampler failure reason.
## Testing
Extend coverage for HTTP and wrapped WebSocket errors, missing or blank provider messages, terminal stream failures with retry headers, and content policy rejections during local and remote compaction on model downshift.
GitOrigin-RevId: 592170ac30c07b0b303a8d5cb15bd35c8f821b55
## What changed
Recognize `access_program_not_enabled` in HTTP 403 responses and response stream errors as a dedicated, non-retryable error. Preserve HTTP diagnostic details and provider stream messages, with a default message when none is supplied.
Stop SSE streams immediately on this error and avoid triggering WebSocket fallback for explicit access program denials. Add a fixed diagnostic label for doctor output and telemetry.
## Testing
Extend coverage for HTTP and WebSocket denials, immediate SSE termination despite retry headers, and doctor diagnostic redaction.
GitOrigin-RevId: 3a41f7bb80ad5e13a87e831b458d17cdd19a4b62
## Why
HTTP 403 responses with `invalid_workspace_selected` were treated as unexpected status errors, allowing retries and compaction fallback to another model after the server rejected the selected workspace.
## What changed
Recognize the code in `detail.code` or `error.code`, falling back to the `x-error-json` header when the body has no code. Classify these 403 responses as `InvalidWorkspaceSelected` and disable retries and compaction model fallback while preserving the response details and HTTP status. Other 403 responses retain their existing retry behavior.
## Testing
Add coverage for body and header error codes, code precedence, HTTP and WebSocket retry behavior, and local and remote compaction during a model downshift.
GitOrigin-RevId: f44a3bee5ef06e601909839868ab99cea6dd7d03
## Why
Local compaction retried invalid requests and server overload errors without retry advice, and used local backoff even when the server supplied `Retry-After`.
## What changed
Use `CodexErr::retry_delay` to decide whether and when to retry local compaction. Honor the original `Retry-After` deadline when present, while retaining the configured retry limit and context-window trimming behavior.
## Testing
Add coverage verifying that manual local compaction does not retry invalid requests or overload responses without retry advice, but retries overload responses with `Retry-After`.
GitOrigin-RevId: abe6cbba661f701b97f8b1ab83b1fe86979f03c0
## Why
Approved filesystem access should make executor skills discoverable and readable for the lifetime of the grant. Turn-scoped access must not authorize persistent plugin servers or hooks, or bypass disabled-plugin policy.
## What changed
- Apply environment-specific session grants to capability discovery and refresh MCP after session grants change.
- Use a separate discovery inventory for skills with turn-scoped grants, keeping plugin servers and hooks on the session inventory. Reuse discovery results across unchanged model steps.
- Preserve disabled-plugin checks for unreadable manifests and symlinked manifest files or directories, including ancestor markers, while retaining standalone skill roots.
## Testing
Add coverage for V1 and V2 skill discovery before approval, after approval, and on the next turn; disabled-plugin ownership checks; discovery cache reuse; and session hooks surviving turn-scoped discovery failure.
GitOrigin-RevId: 929a7f8cb01f4bcfb4bee2c50ae02cd762066b2d