mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
c2508db60db0eae343d12a586dcfbc37e491f122
3051 Commits
-
[codex] Support ui visibility meta for tools (#24700)
## Summary Adds support for the same ui.visibility metadata as resources [spec](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#resource-discovery)
Gabriel Peal ·
2026-05-28 10:24:03 -07:00 -
Fix extension turn item emitter test event ordering (#24936)
## Why PR #24813 added extension `TurnItemEmitter` coverage and introduced a test that records a conversation history item before asserting extension-emitted turn item events. `record_conversation_items()` also emits a `RawResponseItem` event to observers. The test was reading from the same event receiver and expected the next event to be `ItemStarted`, so the test failed reliably once the setup history item was present. ## What Changed Update `passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call` to consume and assert the expected setup `RawResponseItem` before checking the extension `ItemStarted`, `WebSearchBegin`, `ItemCompleted`, and `WebSearchEnd` events. This is test-only and does not change extension runtime behavior. ## Verification - `cargo nextest run --no-fail-fast -p codex-core tools::handlers::extension_tools::tests::passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call`
Michael Bolin ·
2026-05-28 09:59:34 -07:00 -
Reap stale multi-agent slots (#24903)
## Summary - Let `close_agent` clean up an agent that is still registered in `AgentRegistry` even when its underlying thread is already missing. - Preserve the explicit-close boundary: for known stale thread-spawn agents, mark the persisted spawn edge `Closed`, then treat `ThreadNotFound` / `InternalAgentDied` as a successful close so the registry slot can be released. - Add a regression for MultiAgentV2 task-name targets where `close_agent("worker")` succeeds after the worker thread has already disappeared. ## Motivation A worker can disappear from `ThreadManager` while its metadata still exists in the root `AgentRegistry`. Before this change, the close tool failed while trying to subscribe to the missing thread status, so it never reached the cleanup path that releases the registered agent slot. With `agents.max_threads = 1`, an explicit close of that stale task-name agent could fail and leave the session unable to spawn a replacement. ## Scope This PR intentionally does not add automatic stale-agent reaping to `spawn_agent`, `resume_agent`, or `list_agents`. A thread being missing from `ThreadManager` is not the same as an explicit close: persisted open spawn edges are still the durable source of truth for resume and task-name ownership until `close_agent` is called. ## Validation - `just test -p codex-core -E 'test(multi_agent_v2_close_agent_reaps_stale_task_name_target) | test(resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown)'` - `just fix -p codex-core`jif-oai ·
2026-05-28 18:48:43 +02:00 -
extension-api: add TurnItemEmitter to tool calls (#24813)
## Why Extension-contributed tools need to emit visible turn items through Codex's normal event and persistence pipeline. ## What - Add `TurnItemEmitter` to extension `ToolCall`s and route the core implementation through `Session::emit_turn_item_*`. - Hold weak session and turn references so retained tool calls cannot keep host state alive. - Provide a no-op emitter for extension test callers. ## Test Plan - `just test -p codex-core -E 'test(passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call)'` --------- Co-authored-by: jif-oai <jif@openai.com>
sayan-oai ·
2026-05-28 09:13:43 -07:00 -
pakrym-oai ·
2026-05-28 07:23:08 -07:00 -
Add turn error lifecycle contributor (#24916)
Summary - Add TurnErrorInput and TurnLifecycleContributor::on_turn_error to the extension API. - Emit the turn-error lifecycle from core turn error paths, including usage limit failures. - Add direct lifecycle coverage for the emitted error facts and stores. Tests - just fmt - git diff --check - Not run: full tests or clippy (per instructions)
jif-oai ·
2026-05-28 16:13:54 +02:00 -
Add thread start contributor facts (#24915)
Summary: add session source and persistent-state availability to ThreadStartInput; populate them from session init; update existing goal test harness constructors. Tests: just fmt; git diff --check. No full tests or clippy run per request.
jif-oai ·
2026-05-28 16:10:55 +02:00 -
Add Guardian review metrics (#24897)
## Why Guardian reviews already emit analytics events, but we do not expose aggregate OpenTelemetry metrics for review volume, latency, token usage, or terminal outcomes. That makes it harder to monitor Guardian behavior during rollouts and to compare review outcomes by source, action type, session kind, model, and failure mode. ## What Changed - Added Guardian review metric names for count, total duration, time to first token, and token usage in `codex-rs/otel`. - Added `core/src/guardian/metrics.rs` to convert `GuardianReviewAnalyticsResult` into sanitized metric tags covering decision, terminal status, failure reason, approval request source, reviewed action, session kind, risk/outcome, model, reasoning effort, and context/truncation state. - Emitted the new metrics from `track_guardian_review` for each terminal Guardian review result. ## Testing - Added `guardian_review_metrics_record_counts_durations_and_token_usage`, which verifies the emitted count, duration, TTFT, token usage histograms, and tag set through the in-memory metrics exporter.
jif-oai ·
2026-05-28 14:07:25 +02:00 -
[codex] Fix Guardian argument comment lint (#24902)
## Summary - Add the required `/*parent_thread_id*/` argument comment at the Guardian review session test callsite flagged by CI. ## Validation - `just fmt` - Not run: clippy/tests, per request; CI will cover them.
jif-oai ·
2026-05-28 13:38:48 +02:00 -
Thread Guardian cache key through session (#24895)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/session/session.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:40 +02:00 -
Assert Guardian prompt cache key reuse (#24894)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/tests.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:36 +02:00 -
Add Guardian review prompt cache key (#24893)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/review_session.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:25 +02:00 -
Export Guardian prompt cache key helper (#24892)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/mod.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:17 +02:00 -
Stabilize Guardian client cache key handling (#24891)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/client.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:01 +02:00 -
Move memories root setup out of core config (#24758)
## Why Config loading should not create or write-authorize the memories root just because memory support exists. Memory startup is the code path that actually materializes that tree. ## What - Stop creating the memories root during Config load and remove it from legacy workspace-write projections. - Grant the memories root read access only when the memories feature and use_memories are enabled. - Create the memories root inside memories startup before seeding extension instructions. - Update config and startup tests around the ownership boundary. ## Tests - just fmt - just fix -p codex-core - just fix -p codex-memories-write - just test -p codex-core memory_tool_makes_memories_root_readable_without_creating_or_widening_writes workspace_write_includes_configured_writable_root_once_without_memories_root permission_profile_override_keeps_memories_root_out_of_legacy_projection permissions_profiles_allow_direct_write_roots_outside_workspace_root default_permissions_profile_populates_runtime_sandbox_policy - just test -p codex-memories-write memories_startup_creates_memory_root Note: a broader just test -p codex-core run is not clean in this sandbox; it hit missing test_stdio_server plus seatbelt, realtime, and environment-sensitive failures. The changed config tests above pass.
jif-oai ·
2026-05-28 11:51:24 +02:00 -
[codex] Remove redundant SQLite dynamic tool storage (#24819)
## Why Dynamic tools are defined at thread start and already stored in rollout `SessionMeta`, which restores resumed and forked sessions. Persisting the same tools through SQLite creates a second runtime persistence path that is unnecessary prework for the explicit namespace refactor. ## What changed - Restore missing thread-start dynamic tools directly from rollout history, including when SQLite is enabled. - Remove SQLite dynamic-tool reads, writes, backfill, and thread metadata patch plumbing. - Add SQLite-enabled resume integration coverage that verifies a rollout-defined dynamic tool is still sent after resume. ## Compatibility The existing `thread_dynamic_tools` table is intentionally not dropped even though it's now unused. Older Codex binaries are allowed to open databases migrated by newer binaries and still reference this table; dropping it would break that mixed-version path. See [here](https://github.com/openai/codex/blob/main/codex-rs/state/src/migrations.rs#L10-L11). ## Verification - `just test -p codex-state -p codex-rollout -p codex-thread-store` - `just test -p codex-core --test all resume_restores_dynamic_tools_from_rollout_with_sqlite_enabled`
sayan-oai ·
2026-05-27 17:57:32 -07:00 -
Update rmcp to 1.7.0 (#24763)
WIll make it easier to uprev when the new draft spec is supported. Also updates reqwest where needed for compatibility but doesn't update it everywhere since this is already a large diff. The new version of rmcp handles certain kinds of authentication failures differently, this patch includes support for identifying the failing scope in a WWW-Authenticate header.
Adam Perry @ OpenAI ·
2026-05-27 14:52:06 -07:00 -
fix(linux-sandbox): preserve shell cleanup on interruption (#22729)
## Why Interrupted `shell_command` calls can race with the outer tool-dispatch cancellation path. When that happens, the runtime future may be dropped before the spawned process gets a chance to run `SIGTERM` cleanup. For bwrapd-backed Linux sandbox commands, that can leave synthetic protected-path mount bookkeeping such as `.git/.codex` registrations under `/tmp` behind after a TUI interruption. The relevant cancellation points are the outer dispatch race in [`core/src/tools/parallel.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/tools/parallel.rs#L91-L132) and the process shutdown logic in [`core/src/exec.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/exec.rs#L1367-L1393). ## What changed - Keep `shell_command` dispatch alive long enough for the runtime to finish cancellation cleanup instead of immediately returning the synthetic aborted response. - Fold shell-turn cancellation into the existing `ExecExpiration` path in [`core/src/tools/runtimes/shell.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/tools/runtimes/shell.rs#L267-L274), so cancellation and timeout behavior stay centralized. - On cancellation, send `SIGTERM` first, wait briefly for cleanup to run, then hard-kill any remaining descendants in the original process group. - Treat `ESRCH` as an already-gone process-group cleanup case in `codex-utils-pty`, which keeps best-effort teardown from surfacing a stale-process race as an error. ## Verification - `cargo test -p codex-core cancellation` - Added regression coverage for: - `shell_tool_cancellation_waits_for_runtime_cleanup` - `process_exec_tool_call_cancellation_allows_sigterm_cleanup`
viyatb-oai ·
2026-05-27 12:59:11 -07:00 -
chore: enable namespace tools for Bedrock (#24713)
Client-side namespace tools are now supported by bedrock. Enable `namespace_tools` for the Amazon Bedrock provider while continuing to disable unsupported hosted tools such as image generation and web search.
Celia Chen ·
2026-05-27 19:39:01 +00:00 -
[codex] add compaction metadata to turn headers (#24368)
## Summary - Add `request_kind` values for foreground turn, startup prewarm, compaction, and detached memory model requests. - Attach compaction dispatch metadata to local Responses, legacy `/v1/responses/compact`, and remote v2 compact requests. - Add the existing logical context-window identifier as `window_id` on turn-owned model request metadata. - Keep identity fields optional for detached memory requests, while still emitting `request_kind="memory"` in non-git/no-sandbox workspaces. ## Root Cause `x-codex-turn-metadata` has more than one producer. Foreground turns and compaction requests own a real turn and should carry that turn identity. Detached memory stage-one requests do not own a foreground turn, so absent identity fields are valid rather than missing data. Startup websocket prewarm is also a model request, but it has `generate=false` and must not be counted as a foreground turn. `thread_source` or session source identifies where a thread came from (for example review, guardian, or another subagent). `request_kind` identifies what the current outbound model request is doing (`turn`, `prewarm`, `compaction`, or `memory`). A review or guardian thread can issue either a normal turn request or a compaction request, so source cannot replace request kind. ## Behavior / Impact - Ordinary foreground requests send `request_kind="turn"`, their real identity fields, and `window_id="<thread_id>:<window_generation>"`. - Startup websocket warmup requests send `request_kind="prewarm"` so they are not counted as foreground turns. - Compaction requests send `request_kind="compaction"`, their real owning turn identity, the existing `window_id`, and `compaction.{trigger,reason,implementation,phase,strategy}`. - Detached memory stage-one requests send `request_kind="memory"` without `session_id`, `thread_id`, `turn_id`, or `window_id`; when no workspace metadata exists, the kind-only header is still emitted. - `session_id`, `thread_id`, `turn_id`, and `window_id` remain optional in the header schema because detached memory requests do not own a foreground turn or context window. - `window_id` is not a new ID system: it is copied from the already-sent `x-codex-window-id` / WS client metadata value at model-request dispatch time. - Existing `x-codex-window-id` HTTP/WS emission, value format, generation advancement, resume behavior, and fork reset behavior are unchanged. - `request_kind`, `window_id`, and upstream turn-owned identity fields remain schema-owned; input `responsesapi_client_metadata` cannot replace their canonical values. - No table, DAG, export, app-server API, or MCP `_meta` schema changes are included. A compaction attempt stopped by a pre-compact hook issues no model request and therefore has no request header; its outcome remains in analytics events. Status, error, duration, and token deltas also remain analytics fields rather than request-header fields. Future detached-memory attribution using a real initiating turn ID as `trigger_turn_id` is intentionally not part of this PR. ## Sync With Main - Final pushed head `716342e79` is rebased onto `origin/main@0d37db4b2`. - The metadata conflict came from upstream `#24160`, which added `forked_from_thread_id` on the same `turn_metadata` surface. Resolution preserves that field and its protection from client metadata override alongside this PR's request-kind, compaction, and window-id fields. - While resolving the overlapping commits, I removed an accidental recursive model-request overlay and a duplicate detached-memory header builder before completing the rebase. ## Latency / User Experience Boundary - Foreground turns perform no new filesystem, git, or network work. New fields are inserted into metadata already serialized for outgoing requests. - Compaction issues the same model/HTTP requests with the same prompt, model, service tier, and sampling settings; only metadata bytes change. - Startup prewarm already sent metadata; it is now correctly classified as `prewarm`. - Non-git detached memory now sends a small kind-only metadata header rather than no header. - This client diff adds no user-visible latency mechanism beyond negligible serialization and header bytes on already-existing requests. ## Validation On conflict-resolved head `1d35c2cfb` based on `origin/main@487521733`: - `just fmt` (passed) - `just fix -p codex-core` (passed) - `git diff --check origin/main...HEAD` (passed) - `just test -p codex-core -E 'test(turn_metadata) | test(websocket_first_turn_uses_startup_prewarm_and_create) | test(responses_stream_includes_turn_metadata_header_for_git_workspace_e2e) | test(responses_websocket_forwards_turn_metadata_on_initial_and_incremental_create) | test(remote_compact_v2_retries_failures_with_stream_retry_budget) | test(window_id_advances_after_compact_persists_on_resume_and_resets_on_fork)'` (`23 passed`; `bench-smoke` passed) - `just test -p codex-app-server -E 'test(turn_start_forwards_client_metadata_to_responses_request_v2) | test(turn_start_forwards_client_metadata_to_responses_websocket_request_body_v2) | test(auto_compaction_remote_emits_started_and_completed_items)'` (`3 passed`; `bench-smoke` passed) - `just test -p codex-memories-write` (`29 passed`; `bench-smoke` passed)ningyi-oai ·
2026-05-27 11:09:33 -07:00 -
Drop startup context when truncating forked rollouts (#24751)
## Summary - Change last-`n` fork truncation to start at the first fork-turn boundary instead of returning the full rollout when the fork history is shorter than the requested window. - Add coverage for the startup-prefix case in both rollout truncation tests and agent control spawn behavior. - Ensure bounded forked children still rebuild context after the cached prefix is truncated. ## Testing - Added unit coverage for truncation behavior when the parent history is under the requested fork-turn limit. - Added an agent control test covering bounded fork spawn behavior with startup context present. - Not run (not requested).
jif-oai ·
2026-05-27 15:49:08 +02:00 -
fix(auto-review) skip legacy notify for auto review threads (#24714)
## Summary Clear inherited legacy `notify` from Guardian review session config, since we should not be passing auto review threads into `notify` targets. Keeps legacy notify payload and hook runtime behavior unchanged for normal user turns. ## Testing - [x] add a Guardian config regression and dedicated Guardian integration test so review sessions cannot inherit parent notify hooks
Dylan Hurd ·
2026-05-27 07:23:15 +00:00 -
Uprev Rust toolchain pins to 1.95.0 (#24684)
## Summary - Bump the workspace Rust toolchain from `1.93.0` to `1.95.0` across Cargo, Bazel, CI, release workflows, devcontainers, and the Codex environment config. - Refresh `MODULE.bazel.lock` so the Bazel Rust toolchain artifacts match the new version. - Leave purpose-specific toolchains unchanged, including the `argument-comment-lint` nightly and the upstream `rusty_v8` `1.91.0` build pin. - Includes fixes for new lints from `just fix` and a few codex-authored fixes for lints without a suggestion.
Adam Perry @ OpenAI ·
2026-05-26 20:59:47 -07:00 -
fix(core): instrument stalled tool-listing handoff (#24667)
## Why When a turn needs a follow-up request after tool output is recorded, Codex can still appear stuck in `Thinking` before the next `/responses` request is opened. The existing local trace showed the last completed response and the absence of a new backend request, but it did not show whether the stall was in tool-router preparation or later request setup. Issue: N/A (internal incident investigation) ## What Changed Added trace spans around the pre-stream tool-router handoff in `core/src/session/turn.rs`, including the `built_tools` phase and the MCP manager read lock. Added per-server MCP tool-listing spans and trace breadcrumbs in `codex-mcp/src/connection_manager.rs` with startup snapshot / startup-complete state so a pending MCP client is visible in feedback logs instead of looking like a silent hang. ## Verification - `just fmt` - `just test -p codex-mcp` - `just test -p codex-core` (prior full rerun fails in this workspace on unrelated integration tests: code-mode output length expectations, one shell timeout formatting assertion, and shell snapshot timeouts; latest review-fix rerun compiled and passed 1160 tests before I stopped the abnormally slow unrelated suite)
Anton Panasenko ·
2026-05-27 02:00:40 +00:00 -
[codex] Remove obsolete goal continuation turn marker (#24658)
## Why `continuation_turn_id` was introduced to distinguish synthetic goal continuation turns for the no-tool continuation suppression heuristic. #20523 removed that heuristic, but left the marker behind. It is still written and cleared without affecting any runtime decision. ## What Changed - Remove `GoalRuntimeState::continuation_turn_id`. - Remove the marker setter/clearer and their now-no-op start, finish, and abort call sites. ## Testing - Not run yet (deferred at request).
pakrym-oai ·
2026-05-26 17:19:02 -07:00 -
[codex-analytics] add grouped session id to runtime events (#24655)
## Why - Runtime analytics events report `thread_id`, which identifies the individual thread emitting an event - They don't report `session_id`, which identifies the shared session for a root thread and its subagent threads - Emitting both identifiers allows analytics to group related activity ## What Changed - Adds `session_id` to relevant analytics events (thread_initalized, turn, turn_steer, compaction, guardian_review) - Tracks each thread's session ID in the analytics reducer so subsequent thread scoped events emit the same value - Carries the shared session ID through subagent initialization ## Verification - `just test -p codex-analytics` validates event payloads and subagent session grouping. - Focused `codex-app-server` tests validate session IDs for thread, turn, and steer events. - Focused `codex-core` tests validate root and subagent session ID propagation.
marksteinbrick-oai ·
2026-05-26 16:38:46 -07:00 -
Restore legacy image detail values (#24644)
## Why Older persisted rollouts can contain `input_image.detail` values of `auto` or `low` from before `ImageDetail` was narrowed to `high`/`original`. Current deserialization rejects those values, which can make resume skip later compacted checkpoints and reconstruct an oversized raw suffix before the next compaction attempt. Confirmed Sentry reports fixed by this compatibility path: - [CODEX-1H3F](https://openai.sentry.io/issues/7500642496/) - [CODEX-1H6N](https://openai.sentry.io/issues/7501025347/) - [CODEX-1JDP](https://openai.sentry.io/issues/7504549065/) - [CODEX-1HW6](https://openai.sentry.io/issues/7503407986/) ## Background [openai/codex#20693](https://github.com/openai/codex/pull/20693) added image-detail plumbing for app-server `UserInput` so input images could explicitly request `detail: original`. The Slack discussion behind that PR was about ScreenSpot / bridge evals where user input images were resized, while tool output images already had MCP/code-mode ways to request image detail. In review, the intended new API surface was narrowed to `high` and `original`: default to `high`, allow `original` when callers need unchanged image handling, and avoid encouraging new `auto` or `low` usage. That policy still makes sense for newly emitted values. The missing compatibility piece is persisted history. Older rollouts can already contain `auto` and `low`, and resume reconstructs typed history by deserializing those rollout records. Rejecting old values at that boundary causes valid compacted checkpoints to be skipped. This PR restores `auto` and `low` as real variants so old records deserialize and round-trip without being rewritten as `high`, while product paths can continue to default to `high` and avoid emitting `auto` for new behavior. ## What changed - Restored `ImageDetail::Auto` and `ImageDetail::Low` as first-class protocol values. - Preserved `auto`/`low` through rollout deserialization, MCP image metadata, code-mode image output, and schema/type generation. - Kept local image byte handling conservative: only `original` switches to original-resolution loading; `auto`/`low`/`high` continue through the resize-to-fit path while retaining their detail value. - Added regression coverage for enum round-tripping and code-mode `low` detail handling. ## Testing - `just write-app-server-schema` - `just test -p codex-protocol` - `just test -p codex-tools` - `just test -p codex-code-mode` - `just test -p codex-app-server-protocol` - `just test -p codex-core suite::rmcp_client::stdio_image_responses_preserve_original_detail_metadata` - `just test -p codex-core suite::code_mode::code_mode_can_use_mcp_image_result_with_image_helper` - Loaded broken rollouts on local fixed builds, and started/completed new turns. I also attempted `just test -p codex-core`; the local broad run did not finish green: 2559 tests run, 2467 passed, 55 flaky, 91 failed, 1 timed out. The failures were broad timeout/deadline failures across unrelated areas; targeted changed-path core tests above passed.
rhan-oai ·
2026-05-26 16:24:33 -07:00 -
windows-sandbox: remove SandboxPolicy runner plumbing (#23813)
## Why The Windows sandbox runner still carried the old `SandboxPolicy` compatibility path even though core now computes `PermissionProfile`. That meant Windows command-runner execution could only see the legacy projection, so profile-only filesystem rules such as deny globs were not part of the runner input. ## What Changed - Removed the Windows-local `SandboxPolicy` parser/export and deleted `windows-sandbox-rs/src/policy.rs`. - Changed restricted-token capture/session setup, elevated setup, world-writable audit, read-root grant, and command-runner session APIs to accept `PermissionProfile` plus the profile cwd. - Bumped the elevated command-runner IPC protocol to version 2 because `SpawnRequest` now carries `permission_profile` / `permission_profile_cwd` instead of the legacy `policy_json_or_preset` / `sandbox_policy_cwd` fields. - Updated core exec, unified exec, debug-sandbox, TUI setup/grant flows, and app-server setup to pass the actual effective `PermissionProfile`. - Left regression coverage asserting the old IPC policy fields are absent and the runner serializes tagged `PermissionProfile` JSON. ## Verification - `cargo test -p codex-windows-sandbox` - `cargo test -p codex-core windows_sandbox` - `cargo test -p codex-app-server request_processors::windows_sandbox_processor` - `just fix -p codex-windows-sandbox -p codex-core -p codex-app-server -p codex-cli -p codex-tui` - `just fix -p codex-cli -p codex-tui` - `just fix -p codex-windows-sandbox -p codex-tui` - `rg "\\bSandboxPolicy\\b" codex-rs/windows-sandbox-rs` returned no matches. Note: `cargo test -p codex-cli` was attempted but did not reach crate tests because local disk filled while compiling dependencies (`No space left on device`). The targeted clippy pass compiled the affected CLI/TUI surfaces afterward. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23813). * #24108 * __->__ #23813
Michael Bolin ·
2026-05-26 14:56:27 -07:00 -
Curtis 'Fjord' Hawthorne ·
2026-05-26 14:17:43 -07:00 -
Add forked_from_thread_id turn metadata (#24160)
## Why When Codex calls responsesapi, we currently send `session_id`, `thread_id`, and `turn_id` among other things as `client_metadata["x-codex-turn-metadata"]`. This PR adds `forked_from_thread_id` which helps explain the "lineage" of a forked thread. ## What's changed - Track the immediate history source copied into a forked thread through thread/session creation, including subagent and review turn metadata paths. - Include `forked_from_thread_id` in Codex turn metadata while preventing turn-scoped Responses API client metadata from overwriting Codex-owned lineage fields. - Add coverage for fork lineage in turn metadata and the app-server Responses API request path.
Owen Lin ·
2026-05-26 14:05:28 -07:00 -
Add experimental turn additional context (#24154)
## Summary Adds experimental `additionalContext` support to `turn/start` and `turn/steer` so clients can provide ephemeral external context, such as browser or automation state, without turning that plumbing into a visible user prompt or triggering user-prompt lifecycle behavior. ## API Shape The parameter shape is: ```ts additionalContext?: Record<string, { value: string kind: "untrusted" | "application" }> | null ``` Example: ```json { "additionalContext": { "browser_info": { "value": "Active tab is CI failures.", "kind": "untrusted" }, "automation_info": { "value": "CI rerun is in progress.", "kind": "application" } } } ``` The keys are opaque and caller-defined. ## Context Injection When provided, accepted entries are inserted into model context as hidden contextual message items, not as visible thread user-message items. `kind: "untrusted"` entries are inserted with role `user`: ```text <external_${key}>${value}</external_${key}> ``` `kind: "application"` entries are inserted with role `developer`: ```text <${key}>${value}</${key}> ``` Values are not escaped. Each value is truncated to 1k approximate tokens before wrapping. For `turn/start`, accepted additional context is inserted before normal user input. For `turn/steer`, additional context is merged only when the steer includes non-empty user input; context-only steers still reject as empty input. ## Dedupe Strategy `AdditionalContextStore` lives on session state and stores the latest complete additional-context map. Each `turn/start` or non-empty `turn/steer` treats its `additionalContext` as the current complete set of values. Entries are injected only when the key is new or the exact entry for that key changed, including `value` or `kind`. After merging, the store is replaced with the provided map, so omitted keys are removed from the retained set and can be injected again later if reintroduced. Omitting `additionalContext`, passing `null`, or passing an empty object resets the store to empty and injects nothing. ## What Changed - Threads experimental v2 `additionalContext` through app-server into core turn start and steer handling. - Adds separate contextual fragment types for untrusted user-role context and application developer-role context. - Uses pending response input items so additional context can be combined with normal user input without treating it as prompt text. - Adds integration coverage for start/steer flow, role routing, dedupe/reset behavior, deletion/re-add behavior, hook-blocked input behavior, empty context-only steer rejection, external-fragment marker matching, and truncation.pakrym-oai ·
2026-05-26 13:02:34 -07:00 -
standalone websearch extension (#23823)
## Summary Add the extension-backed standalone `web.run` tool so Codex can call the standalone search endpoint through the `codex-api` search client and return its encrypted output to Responses. - gate the new tool behind `standalone_web_search` - install the extension in the app-server thread registry and hide hosted `web_search` when standalone search is enabled for OpenAI providers so the two paths stay mutually exclusive - build search context from persisted history using a small tail heuristic: previous user message, assistant text between the last two user turns capped at about 1k tokens, and current user message ## Test Plan - `cargo test -p codex-web-search-extension` - `cargo test -p codex-api` - `cargo test -p codex-core hosted_tools_follow_provider_auth_model_and_config_gates`
sayan-oai ·
2026-05-26 11:12:24 -07:00 -
Move memory state to a dedicated SQLite DB (#24591)
## Summary Generated memory rows and their stage-one/stage-two job state currently live in `state_5.sqlite` alongside thread metadata. That makes memory cleanup and regeneration share the main state schema even though those rows are memory-pipeline data and can be rebuilt independently from the durable thread records. This PR moves the memory-owned tables into a dedicated `memories_1.sqlite` runtime database while keeping thread metadata in `state_5.sqlite`. ## Changes - Adds a separate memories DB runtime, migrator, path helpers, telemetry kind, and Bazel compile data for `state/memory_migrations`. - Introduces `MemoryStore` behind `StateRuntime::memories()` and moves memory table/job operations onto that store. - Drops the old memory tables from the state DB and recreates their schema in `state/memory_migrations/0001_memories.sql`. - Updates memory startup, citation usage tracking, rollout pollution handling, `debug clear-memories`, and app-server `memory/reset` to operate through the memories DB. - Preserves cross-DB behavior by hydrating thread metadata from the state DB when selecting visible memory outputs and checking stage-one staleness. ## Verification - Added/updated `codex-state` tests for deleted-thread memory visibility and already-polluted phase-two enqueue behavior. - Updated `debug clear-memories`, app-server `memory/reset`, and memories startup tests to seed and assert memory rows through `memories_1.sqlite`.
jif-oai ·
2026-05-26 20:07:25 +02:00 -
feat: add manual and remote_v2 tags to compaction metric (#24608)
## Why `codex.task.compact` only distinguished `local` vs `remote`, which made it hard to answer simple counter questions in Statsig. Manual `/compact` and automatic compaction were collapsed together, and the legacy remote path was also collapsed with `remote_compaction_v2`. ## What Changed - route `codex.task.compact` through a shared helper in `core/src/tasks/mod.rs` - add a `manual=true|false` tag so manual and automatic compaction can be counted separately - split the remote tag into `remote` and `remote_v2` - emit the metric from the inline auto-compaction path in `core/src/session/turn.rs` as well as the manual `CompactTask` path in `core/src/tasks/compact.rs` - add focused unit coverage for the new tag shapes in `core/src/tasks/mod_tests.rs` ## Verification - added unit coverage in `core/src/tasks/mod_tests.rs` covering manual `remote_v2` tags and automatic `local` tags
jif-oai ·
2026-05-26 18:47:42 +02:00 -
tui: add named permission profile picker (#21559)
## Why Users who opt into named permission profiles through `default_permissions` or `[permissions.*]` should stay in named-profile semantics when they open `/permissions`. The legacy picker rewrites those users into anonymous preset state, which loses the active profile identity and hides custom configured profiles. ## What changed - Switch `/permissions` to a profile-aware picker when profile mode is active. - Show friendly built-in labels instead of raw `:` profile syntax. - Include configured custom profiles and their descriptions in the picker. - Route selections through the split TUI profile-selection flow below this PR. - Add TUI snapshots and regression coverage for built-ins, custom profiles, and conflicting legacy runtime overrides. ## Stack 1. [#22931](https://github.com/openai/codex/pull/22931): runtime/session/network propagation for active permission profiles. 2. [#23708](https://github.com/openai/codex/pull/23708): TUI selection plumbing and guardrail flow. 3. **This PR**: profile-aware `/permissions` menu and custom profile display. ## UX impact In profile mode, `/permissions` shows the same human-facing built-ins users already know: ```text Default Auto-review Full Access Read Only locked-down web-enabled ``` Selecting `locked-down` keeps `active_permission_profile = Some("locked-down")`; selecting a built-in keeps the friendly label while switching to its named built-in profile. ## Screenshots Live `$test-tui` smoke screenshots uploaded through GitHub attachments: **Profile mode with built-ins and custom profiles** <img width="832" alt="Profile mode permissions picker with custom profiles" src="https://github.com/user-attachments/assets/58b72431-418c-4839-9e39-575076db4c8f" /> **Legacy mode remains anonymous preset picker** <img width="1232" alt="Legacy permissions picker" src="https://github.com/user-attachments/assets/95f413ab-4cee-411c-9afb-92580a885c97" /> <img width="1296" height="906" alt="image" src="https://github.com/user-attachments/assets/ea381a78-9904-4aa2-828f-b7f2e43f60f2" /> <img width="705" height="207" alt="Screenshot 2026-05-18 at 2 58 00 PM" src="https://github.com/user-attachments/assets/2fa6dd71-0296-449e-a6de-a72d78a1cb70" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack.
viyatb-oai ·
2026-05-26 16:39:55 +00:00 -
feat: gate dedicated memories tools in config (#24600)
## Why The memories extension already has dedicated `list`, `read`, `search`, and `add_ad_hoc_note` tools, but app-server registration was still disabled. The memories app collaborator needs an explicit config switch so those native extension tools can be exposed intentionally, without making ordinary memory prompt usage automatically register the dedicated tool surface. ## What changed - Added `[memories].dedicated_tools`, defaulting to `false`, to `MemoriesToml` / `MemoriesConfig`. - Regenerated `core/config.schema.json` for the new setting. - Registered the memories extension as a `ToolContributor`, while keeping tool contribution gated on both memories being enabled and `dedicated_tools = true`. - Added tests for the disabled default, the enabled dedicated-tools path, and installer registration. ## Verification - `just test -p codex-config -p codex-memories-extension`
jif-oai ·
2026-05-26 18:18:58 +02:00 -
Move MCP tool naming mode into manager (#21576)
## Why The `non_prefixed_mcp_tool_names` feature should be applied where MCP tools become model-visible, not by remapping names later in core. Keeping the decision in `McpConnectionManager` construction makes `ToolInfo` the single shaped view that spec building, deferred tool search, routing, and unavailable-tool placeholders can consume directly. This also preserves the existing external behavior while the feature is off, and keeps the feature-on behavior for code mode and hooks explicit at the manager boundary. ## What Changed - Add `McpToolNameMode` to `codex-mcp` and flow it through `McpConfig` into `McpConnectionManager::new`. - Normalize MCP `ToolInfo` names in the manager using either legacy-prefixed namespaces or non-prefixed namespaces; the legacy path adds `mcp__` without restoring the old trailing namespace suffix. - Remove the core-side MCP name remapping path so specs, tool search, session resolution, and unavailable-tool placeholder construction use the manager-provided `ToolName` values directly. - Keep code mode flattening on the `__` namespace separator. - Preserve hook compatibility by giving non-prefixed MCP hook names legacy `mcp__...` matcher aliases. - Add/adjust integration and unit coverage for non-prefixed code-mode behavior, hook matching with the feature on and off, and manager-level legacy prefixing. ## Testing - `cargo test -p codex-mcp --lib` - `cargo test -p codex-core --lib tools::spec::tests -- --nocapture` - `cargo test -p codex-core --lib mcp_tools -- --nocapture` - `cargo test -p codex-core --lib mcp_tool_exposure -- --nocapture` - `cargo test -p codex-core --test all mcp_tool -- --nocapture` - `cargo test -p codex-core --test all search_tool -- --nocapture` - `cargo test -p codex-core --test all hooks_mcp -- --nocapture` - `cargo test -p codex-core --test all code_mode_uses_non_prefixed_mcp_tool_names_when_feature_enabled -- --nocapture` - `cargo test -p codex-tools` - `cargo test -p codex-features`
pakrym-oai ·
2026-05-26 08:21:15 -07:00 -
[codex] Make active turn task singular (#24105)
## Why `ActiveTurn` already runs at most one task: starting a task requires that no task is present, and replacement aborts existing work first. Representing that state as an `IndexMap` leaves a multi-task shape for a single-task invariant and makes each lifecycle lookup operate like a collection lookup. The slot remains optional because goal continuation uses an empty active turn as a reservation while deciding whether to start continuation work. ## What changed - Replace `ActiveTurn.tasks` with `task: Option<RunningTask>`. - Update task abort/completion, session lookup and steering, input-queue matching, goal reservation, and network-approval lookup to operate on the singular slot. - Mutate the singular task slot directly instead of retaining collection-era add/remove/take helpers. - Record token usage on the completing active task span without a regular-task-only opt-in flag. ## Validation - `cargo test -p codex-core --lib session::tests::steer_input` - `cargo test -p codex-core --lib session::tests::abort_empty_active_turn_preserves_pending_input` - `cargo test -p codex-core --lib session::tests::queued_response_items_for_next_turn_move_into_next_active_turn` - `cargo test -p codex-core --lib session::tests::active_goal_continuation_runs_again_after_no_tool_turn` - `cargo test -p codex-core --lib session::tests::abort_regular_task_emits_turn_aborted_only` - `cargo test -p codex-core --lib session::input_queue::tests`
pakrym-oai ·
2026-05-26 08:20:58 -07:00 -
jif-oai ·
2026-05-26 11:22:18 +02:00 -
centralize Responses retry policy (#24131)
## Why #23951 added remote compaction v2 retries, but it left the retry and WS -> HTTPS fallback behavior duplicated between normal Responses turns and compaction. This follow-up centralizes the common retry handling so future changes to fallback, retry delay, retry notifications, and retry sleep do not have to be kept in sync across both callsites. ## What changed - Added `core/src/responses_retry.rs` with a shared handler for retryable Responses stream errors. - Reused that handler from normal turn sampling and remote compaction v2. - Kept each callsite responsible for its retry budget: normal turns still use `stream_max_retries`, while compaction v2 still uses `min(stream_max_retries, 2)`. - Preserved caller-specific behavior around non-retryable errors, context-window errors, usage-limit errors, and compact-specific final failure logging. The shared handler now owns: - WS -> HTTPS fallback warning emission - retry delay selection, including server-requested stream retry delay - retry logging - first-WebSocket-retry notification suppression - `Reconnecting... n/max` stream-error notification - sleeping before the next retry attempt ## Verification - `cargo test -p codex-core remote_compact_v2` - `cargo test -p codex-core websocket_fallback` - `just fix -p codex-core` Did not run the full workspace test suite. --------- Co-authored-by: jif-oai <jif@openai.com>
rhan-oai ·
2026-05-26 11:01:18 +02:00 -
chore: stop consuming legacy config profiles (#24076)
## Why The old config-profile mechanism should no longer influence runtime behavior now that profile selection has moved to file-based `--profile` config files. Core already rejects a selected legacy `profile = "..."` with a migration error in [`core/src/config/mod.rs`](https://github.com/openai/codex/blob/d6451fcb79edc4a71bc9e811bcda06fd3c36562e/codex-rs/core/src/config/mod.rs#L2521-L2529), but a few residual consumers still read legacy `[profiles.*]` data while performing managed-feature checks and personality migration. That kept dead legacy profile state relevant after selection had been removed, and could make personality migration depend on a stale or missing old profile. ## What changed - Stop scanning legacy `[profiles.*]` feature settings when validating managed feature requirements. - Make personality migration consider only top-level `personality` and `model_provider` settings. - Remove the now-unused `ConfigToml::get_config_profile` helper. - Update personality migration coverage to verify that legacy profile personality fields and missing legacy profile names no longer affect that migration path. This keeps the legacy `profile` / `profiles` config shape available for the remaining compatibility and migration diagnostics; it only removes these behavior consumers. ## Verification - Updated `core/tests/suite/personality_migration.rs` for the new legacy-profile behavior. - Focused test command: `cargo test -p codex-core personality_migration`.
jif-oai ·
2026-05-26 10:34:43 +02:00 -
code-mode: merge stored values by key (#24159)
## Summary Change code-mode stored value updates to merge writes by key instead of replacing the session's complete stored-value map after each cell completes. Previously, each cell received a snapshot of stored values and returned the complete resulting map. When multiple cells ran concurrently, a later completion could overwrite values written by another cell because it committed an older snapshot. This change moves stored-value ownership into `CodeModeService`: - Each runtime starts from the service's current stored values. - Runtime completion reports only keys written by that cell. - The service merges those writes into the current stored-value map on successful completion. - Core no longer replaces its stored-value state from a cell result. As a result, concurrently executing cells can update different stored keys without clobbering one another. The move into CodeModeService is motivated by a desire to have this lifetime tied to a new lifetime object on that side in a subsequent PR.
Channing Conger ·
2026-05-22 19:09:02 -07:00 -
Default function tools into tool hooks (#23757)
# Why `PreToolUse`, `PostToolUse`, and `updatedInput` coverage for local function tools currently depends on each handler remembering to wire up the hook contract itself. That makes coverage easy to miss as new function tools are added, even though most of them share the same basic shape: a model-facing function call with JSON arguments. # What This makes `CoreToolRuntime` provide the default hook contract for ordinary local function tools: - build generic `PreToolUse` and `PostToolUse` payloads from the function tool name and arguments - apply `updatedInput` rewrites back into function-tool arguments through the same default path - let tool outputs override the post-hook input or response when they have a more stable hook-facing contract The exceptions stay explicit: - hosted tools remain outside the generic local function path - code-mode `wait` and `write_stdin` opt out for now - `PostToolUse` feedback replaces only the model-visible response, so code mode keeps its typed tool result With the generic path in place, the MCP and extension-tool adapters no longer need their own duplicate pre/post hook plumbing. The new coverage exercises the registry default plus end-to-end local function behavior for pre-hook blocking, `updatedInput` rewriting, and post-hook context.
Abhinav ·
2026-05-23 00:56:58 +00:00 -
package: include zsh fork in Codex package (#23756)
## Why The package layout gives Codex a stable place for runtime helpers that should travel with the entrypoint. `shell_zsh_fork` still required users to configure `zsh_path` manually, even though we already publish prebuilt zsh fork artifacts. This PR builds on #24129 and uses the shared DotSlash artifact fetcher to include the zsh fork in Codex packages when a matching target artifact exists. Packaged Codex builds can then discover the bundled fork automatically; the user/profile `zsh_path` override is removed so the feature uses the package-managed artifact instead of a legacy path knob. ## What Changed - Added `scripts/codex_package/codex-zsh`, a checked-in DotSlash manifest for the current macOS arm64 and Linux zsh fork artifacts. - Taught `scripts/build_codex_package.py` to fetch the matching zsh fork artifact and install it at `codex-resources/zsh/bin/zsh` when available for the selected target. - Added package layout validation for the optional bundled zsh resource. - Added `InstallContext::bundled_zsh_path()` and `InstallContext::bundled_zsh_bin_dir()` for package-layout resource discovery. - Threaded the packaged zsh path through config loading as the runtime `zsh_path` for packaged installs, and removed the config/profile/CLI override path. - Kept the packaged default zsh override typed as `AbsolutePathBuf` until the existing runtime `Config::zsh_path` boundary. - Updated app-server zsh-fork integration tests to spawn `codex-app-server` from a temporary package layout with `codex-resources/zsh/bin/zsh`, matching the new packaged discovery path instead of setting `zsh_path` in config. - Switched package executable copying from metadata-preserving `copy2()` to `copyfile()` plus explicit executable bits, which avoids macOS file-flag failures when local smoke tests use system binaries as inputs. ## Testing To verify that the `zsh` executable from the Codex package is picked up correctly, first I ran: ```shell ./scripts/build_codex_package.py ``` which created: ``` /private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/ ``` so then I ran: ``` /private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/bin/codex exec --enable shell_zsh_fork 'run `echo $0`' ``` which reported the following, as expected: ``` /private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/codex-resources/zsh/bin/zsh ``` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23756). * #23768 * __->__ #23756
Michael Bolin ·
2026-05-22 17:54:07 -07:00 -
[codex] Remove external client session reset plumbing (#24157)
## Why The turn loop no longer needs to decide when a `ModelClientSession` should reset its websocket state after compaction. That reset behavior belongs inside the model client, where the websocket cache and retry state are owned. The repo guidance now calls this out explicitly so future changes let the incremental request logic decide whether the previous request can be reused. ## What Changed - Removed the `reset_client_session` return value from pre-sampling and auto-compact helpers in `core/src/session/turn.rs`. - Changed compaction helpers to return `CodexResult<()>` so callers only handle success or failure. - Made `ModelClientSession::reset_websocket_session` private to `core/src/client.rs`, leaving it callable only from model-client internals. - Added `AGENTS.md` guidance not to call `reset_client_session` unnecessarily. ## Validation - `just test -p codex-core session::turn`
pakrym-oai ·
2026-05-22 16:46:25 -07:00 -
[codex] Use TurnInput for session task input (#24151)
## Why The idea here is to erase the difference between initial and followup inputs to a turn. Followup inputs are already represented as TurnInput. Eventual goal is not to have explicit on task input at all and pull everything from input Q. ## What Changed - Changes `SessionTask::run` and the erased `AnySessionTask::run` path to accept `Vec<TurnInput>`. - Wraps user-submitted spawn input as `TurnInput::UserInput` at the session task start boundary. - Updates `run_turn` to record initial `TurnInput` using the same hook and recording path used for pending input. - Keeps review-specific conversion local to `ReviewTask`, where the sub-Codex one-shot API still expects `Vec<UserInput>`. - Moves the synthetic compact prompt into `CompactTask` and starts compact tasks with empty task input. ## Validation - `cargo check -p codex-core` - `just test -p codex-core -E 'test(task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input) | test(queued_response_items_for_next_turn_move_into_next_active_turn) | test(steered_input_reopens_mailbox_delivery_for_current_turn)'`
pakrym-oai ·
2026-05-22 15:21:08 -07:00 -
[codex-analytics] split compaction v2 analytics implementation (#24146)
## What changed - Add a distinct `responses_compaction_v2` value for `CodexCompactionEvent.implementation`. - Emit that value from the remote compaction v2 path. - Keep local compaction as `responses` and legacy `/responses/compact` as `responses_compact`. ## Why Remote compaction v2 and local prompt-based compaction were both reported as `responses`, which made the analytics table collapse two different compaction mechanisms into one implementation bucket. ## Validation - `just fmt` - `just test -p codex-analytics` `just test -p codex-core` was started locally, but this PR is intentionally being pushed for CI to finish the remaining validation.
rhan-oai ·
2026-05-22 21:34:22 +00:00 -
Add trace_id to TurnStartedEvent (#23980)
## Why [Recent PR](https://github.com/openai/codex/pull/22709) removed `trace_id` from `TurnContextItem`. ## What changed - Add to `TurnStartedEvent` so rollout consumers can correlate turns with telemetry traces. - Note that the branch name is out of date because I originally re-added to `TurnContextItem`, but we decided to move it to `TurnStartedEvent`. ## Verification - `cargo test -p codex-protocol` - `cargo test -p codex-core --lib regular_turn_emits_turn_started_without_waiting_for_startup_prewarm` - `cargo test -p codex-core --test all emits_warning_when_resumed_model_differs` - `cargo test -p codex-rollout` - `cargo test -p codex-state`
mchen-oai ·
2026-05-22 13:10:56 -07:00 -
Add new enterprise requirement gate (#23736)
Add new enterprise requirement gate. Validation: - `cargo test -p codex-config --lib` - `cargo test -p codex-app-server-protocol --lib` - `cargo test -p codex-tui --lib debug_config` - `cargo test -p codex-app-server --lib` *(fails: stack overflow in `in_process::tests::in_process_start_initializes_and_handles_typed_v2_request`; reproduces when run alone)*
adams-oai ·
2026-05-22 11:33:44 -07:00 -
retry remote compaction v2 requests (#23951)
## Why Remote compaction v2 sends a normal `/responses` request with a compaction trigger. It should follow the retry semantics used by normal Responses streaming calls for transient stream/request failures, while keeping a smaller per-transport retry budget because compact attempts can run much longer than normal turns. ## What changed - Add a v2 compaction retry loop that uses `stream_max_retries`, matching normal Responses turn retry mechanics. - Cap the compact v2 retry budget at 2 retries per transport with `min(stream_max_retries, 2)`. - Retry retryable request-open and post-open stream collection failures through the same loop. - Use the existing 200ms exponential backoff and requested retry delay handling used by normal turn retries. - Emit the same `Reconnecting... n/max` stream-error notification pattern. - Fall back from WebSockets to HTTPS after the compact v2 stream retry budget is exhausted, then reset the retry counter for HTTPS. - Keep final remote-compaction failure logging after retries/fallback are exhausted. - Treat compact stream EOF before `response.completed` as a retryable stream failure. - Add compact v2 regression coverage with `request_max_retries = 0` and `stream_max_retries = 2`, covering both request-open failure and opened-stream EOF in one end-to-end test. ## Tests - `just fmt` - `cargo test -p codex-core remote_compact_v2` - `just fix -p codex-core`
rhan-oai ·
2026-05-22 10:14:14 -07:00