mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
dbd2857f4bdd220b986f7d6bf69fbcd7dc34b520
3300 Commits
-
[codex] Add optional IDs to response items (#28812)
## Why `ResponseItem` variants do not have a consistent internal ID shape: some variants carry required IDs, some carry optional IDs, and some cannot represent an ID at all. The existing fields also use inconsistent serde, TypeScript, and JSON-schema annotations. A single enum-level access path is needed before history recording can assign and retain IDs. This PR establishes that internal model only. It intentionally does not generate or serialize IDs; allocation and wire persistence are isolated in the stacked follow-up. ## What changed - Give every concrete `ResponseItem` variant an `Option<String>` ID field. - Apply the same internal-only annotations to every ID field: `#[serde(default, skip_serializing)]`, `#[ts(skip)]`, and `#[schemars(skip)]`. - Add `ResponseItem::id()` and `ResponseItem::set_id()` as the shared accessors. - Preserve IDs when history items are rewritten for truncation. - Adapt consumers that previously assumed reasoning and image-generation IDs were required. - Regenerate app-server schemas so the hidden fields are represented consistently. The serde catch-all `ResponseItem::Other` remains ID-less because it must remain a unit variant. ## Test plan - `cargo check --tests -p codex-core -p codex-api -p codex-rollout-trace -p codex-image-generation-extension` - `just test -p codex-protocol` - `just test -p codex-app-server-protocol` - `just test -p codex-api -p codex-rollout-trace -p codex-image-generation-extension` - `just test -p codex-core event_mapping`
pakrym-oai ·
2026-06-17 18:27:43 -07:00 -
[codex] trace tools build latency (#28782)
Add more tracing spans around tool building.
Owen Lin ·
2026-06-17 14:53:54 -07:00 -
unified-exec: preserve PathUri through exec-server (#28681)
## Why It should be possible for app-server to handle "foreign" OS paths in unified_exec working directories, allowing e.g. a Linux app-server to run processes on e.g. a Windows exec-server. ## What Convert the core unified_exec cwd values to use `PathUri`. Adds fallible path conversion in several places to try to minimize the scope of this change. The only time this change suppresses errors from converting `PathUri` to an `AbsolutePathBuf` is when the turn is configured with no sandboxing at all to allow us to make progress testing without sandboxing. Future changes to apply_patch and sandboxing will clean up these error paths. A tool's cwd is resolved from joining a model-provided workdir to the environment's cwd. When using `AbsolutePathBuf::join()`, an absolute-path workdir would overwrite the environment's cwd and we would resolve permissions/sandboxing against the model-provided path. This change extends `PathUri::join()` to also treat an absolute rhs as an override of the base/lhs. This also removes some coverage from the remove_env_windows tests until a follow-up converts foreign paths in command exec events correctly. ## Breaking Changes When using `AbsolutePathBuf::join()` for workdir resolution, we ended up resolving tilde-prefixed paths against the app-server's `$HOME`, e.g. `~/foo/bar` becomes `/home/anp/foo/bar`. It's difficult to do this with `PathUri` joining, so after offline discussion this PR no longer implements it. A quick check of some power users' rollouts suggests that models don't actually generate home-prefixed absolute working directories for their spawns, so this shouldn't have any real blast radius.
Adam Perry @ OpenAI ·
2026-06-17 19:36:16 +00:00 -
[codex] Restore thread recency with compatible migration history (#28671)
## Summary - Revert #28655, restoring the thread `recencyAt` behavior introduced by #27910. - Move `threads_recency_at` to migration 0039 so it no longer collides with `external_agent_config_imports` at version 0038. - Repair databases that already applied the recency migration as version 38 by moving the matching migration-history row to version 39 before SQLx validation. The current version-38 migration can then apply normally. ## Validation - `just test -p codex-state migrations::tests::repairs_recency_migration_that_was_applied_as_version_38` - `just test -p codex-state -p codex-rollout -p codex-thread-store -p codex-app-server-protocol -p codex-tui`: 3,439 passed; six TUI tests could not open the machine's existing read-only incident database at `~/.codex/sqlite/state_5.sqlite`. - `just fix -p codex-state` - `just fmt` - Verified that state migration versions are unique.
Jeremy Rose ·
2026-06-17 18:52:18 +00:00 -
Scope command approvals by execution environment (#28738)
## Why Command approval cache keys included the command and working directory, but not the execution environment. An approval for `/workspace` locally could therefore be reused for the same command and path on an executor. ## What changed - Include the selected environment ID in shell and unified-exec approval cache keys. - Carry that ID through the normal command approval request so clients can show which environment is being approved. - Expose the environment through app-server as a required nullable `environmentId` and show it in the inline TUI approval prompt. - Keep older recorded approval events compatible when the environment is absent. For example, `echo ok` in local `/workspace` and `echo ok` in executor `/workspace` now produce different approval keys and separate prompts. ## Scope This PR does not change network approvals, Guardian review actions, MCP elicitation, full-screen TUI rendering, or environment-ID validation. Remote `shell_command` execution itself remains in #28722; this PR only makes its approval key environment-aware.
jif ·
2026-06-17 19:52:43 +02:00 -
Run fs helper through Windows sandbox wrapper (#28359)
## Why This is the final PR in the Windows fs-helper sandbox stack and contains the actual bug fix. The exec-server filesystem helper is a direct-spawn path: it asks `SandboxManager` for a `SandboxExecRequest`, then launches the returned argv itself. That works on macOS and Linux because the transformed argv is already a self-contained sandbox wrapper. On Windows, the transformed request carried `WindowsRestrictedToken` metadata, but the direct-spawn fs-helper runner still launched the helper argv directly. That means Windows filesystem built-ins backed by the fs-helper could run with the parent Codex process permissions instead of the configured Windows sandbox. This PR makes the direct-spawn transform produce a self-contained Windows wrapper argv before fs-helper launches it. ## What Changed - Added `SandboxManager::transform_for_direct_spawn()` for callers that launch the returned argv themselves. - Wrapped Windows restricted-token direct-spawn requests with `codex.exe --run-as-windows-sandbox` and then marked the outer request as unsandboxed, matching the macOS/Linux wrapper argv shape. - Updated `exec-server/src/fs_sandbox.rs` to use the direct-spawn transform for fs-helper launches. - Materialized the inner `codex.exe --codex-run-as-fs-helper` executable into `.sandbox-bin` so the sandboxed user can run it. - Carried runtime workspace roots through `FileSystemSandboxContext` as `PathUri` values so `:workspace_roots` policies resolve correctly without sending native client paths over exec-server JSON. - Preserved wrapper setup identity environment needed by Windows sandbox setup without changing the serialized inner helper environment. ## Verification - `just bazel-lock-update` - `just bazel-lock-check` - `just test -p codex-sandboxing transform_for_direct_spawn_windows` - `just test -p codex-exec-server fs_sandbox::tests` - `just fix -p codex-windows-sandbox -p codex-sandboxing -p codex-exec-server -p codex-core -p codex-file-system` Local note: `just fmt` completed Rust formatting, but this workstation still fails the non-Rust formatter phases because uv cannot open its cache and the local buildifier/dotslash path is missing.
iceweasel-oai ·
2026-06-17 10:00:42 -07:00 -
Replace SkillsManager with SkillsService (#28705)
## Why Host skill discovery was still exposed as a manager even though it is a process-owned service shared by sessions, the app-server catalog, and file-watcher invalidation. The skills extension also consumed an ad hoc loaded-skills wrapper instead of a named immutable snapshot. ## What changed - replace `SkillsManager` with concrete `SkillsService` - make the service cache and return immutable `HostSkillsSnapshot` values - migrate the skills extension host provider to the snapshot boundary - migrate app-server catalog, watcher, and invalidation paths to the service This keeps the service limited to host discovery, caching, roots, and invalidation. Catalog rendering and invocation remain extension responsibilities for the next stacked change.
jif ·
2026-06-17 17:01:06 +02:00 -
Add join key for MAv2 inter-agent messages (#28561)
## Summary This keeps inter-agent communication on the existing raw response item path and adds a join key for MAv2 tool calls. MAv2 `spawn_agent`, `send_message`, and `followup_task` now stamp the originating tool call id into `ResponseItemMetadata.source_call_id` on the raw `ResponseItem::AgentMessage`. App-server clients can join that raw item back to the existing tool/activity event by call id, while using the raw agent message's existing sender, receiver, and content fields. No new app-server `ThreadItem` or notification type is added. ## Tests - `just fmt` - `just write-app-server-schema` - `just test -p codex-protocol` - `just test -p codex-app-server-protocol` - `just test -p codex-core multi_agent_v2_spawn_returns_path_and_send_message_accepts_relative_path` - `just test -p codex-core multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn` - `just fix -p codex-protocol` - `just fix -p codex-app-server-protocol` - `just fix -p codex-core`
jif ·
2026-06-17 14:48:56 +02:00 -
[codex] Persist built-in image results reported as generating (#28656)
## Why #27920 stopped persisting image-generation items unless their status was `completed`, preventing failed standalone extension items with empty results from being saved. Built-in image generation can instead emit a terminal `response.output_item.done` containing a complete base64 PNG while the item status remains `generating`. In that case, app-server emits no `savedPath`, so Codex Apps can render the inline image but cannot expose a file artifact. ## What changed - Persist image-generation items whenever `result` contains image data. Failed terminal items still have empty results and remain unpersisted. - Update the existing built-in image-generation integration test to cover a terminal `generating` item and verify both `saved_path` and the written PNG bytes. ## Validation - Confirmed with a raw built-in websocket trace: the image progressed through `in_progress`, `generating`, and `partial_image`, then emitted one `response.output_item.done` with `status: "generating"` and a complete PNG result. - `just test -p codex-core builtin_image_generation_call_persisted` is currently blocked before test execution by a pre-existing compile error in `thread-store/src/thread_metadata_sync.rs:171`.
Won Park ·
2026-06-17 06:03:00 +00:00 -
core: remove redundant TurnContext and Prompt fields (#28638)
## Why `TurnContext` had accumulated dead fields and cached projections of values already owned by its per-turn `Config` or `ModelInfo`. Keeping both copies made ownership unclear and allowed artificial split-brain states, such as a compatibility hash differing from the model metadata it came from. `Prompt` similarly carried a write-only personality after personality selection had already been materialized into its base instructions. This makes the canonical owner explicit: configuration-backed values come from `config`, model-derived values come from `model_info`, and prompts contain only data consumed by request construction. ## What changed - Remove the unused `ghost_snapshot`, `codex_self_exe`, and `thread_source` fields. - Remove duplicate `comp_hash`, `truncation_policy`, `features`, `shell_environment_policy`, `codex_linux_sandbox_exe`, `compact_prompt`, and `tool_mode` fields. - Read those values directly from `TurnContext::config` or `TurnContext::model_info` at their consumers. - Remove the write-only `Prompt::personality` field and its constructor assignments. - Preserve review-turn inheritance of the parent turn's shell policy, Linux sandbox executable, and compact prompt through the review config. ## Testing - `cargo check -p codex-core --tests`
pakrym-oai ·
2026-06-16 22:17:24 -07:00 -
Revert thread recencyAt for sidebar ordering (#28655)
## Why Revert #27910 to remove the newly introduced thread `recencyAt` persistence and API behavior from `main`. ## What changed This reverts commit `fac3158c2a783095768076489815f361fa9b0db4`, including the state migration, thread-store propagation, app-server API surface, generated schemas, and related tests. ## Validation Not run before opening; relying on CI for the initial fast signal.
pakrym-oai ·
2026-06-16 21:39:30 -07:00 -
[codex] core: restore absolute turn context cwd (#28629)
## Why #28152 jumped the gun on moving the rollout format to store URIs, and would likely break compat with some features that don't go through the same types as the core logic. ## What Make `TurnContextItem.cwd` an `AbsolutePathBuf` again, remove test added for `PathUri` serialization in rollouts. Also drops a bunch of error paths that are no longer needed.
Adam Perry @ OpenAI ·
2026-06-16 19:05:26 -07:00 -
Add thread recencyAt for sidebar ordering (#27910)
## Summary Add a server-owned `recencyAt` timestamp and `recency_at` thread-list sort key for product recency ordering while preserving the existing meaning of `updatedAt` as the latest persisted thread mutation. This is the server-side alternative to #27697. Rather than narrowing `updatedAt`, clients can sort the sidebar by `recency_at` and continue treating `updatedAt` as mutation time. Paired Codex Apps PR: [openai/openai#1024599](https://github.com/openai/openai/pull/1024599) ## Contract - `recencyAt` initializes when a thread is created. - A turn start advances `recencyAt` monotonically. - Commentary, agent output, tool results, token/accounting updates, turn completion, archive, unarchive, resume, and generic metadata writes do not advance it. - `updatedAt` retains its existing behavior and continues to advance for persisted thread mutations. - Current servers populate `recencyAt`; the response field is optional in generated TypeScript so clients connected to older servers can fall back to `updatedAt`. - Filesystem-only fallback uses existing updated/mtime ordering when SQLite is unavailable. ## Persistence and compatibility Migration 0038 adds second- and millisecond-precision recency columns, backfills them from the existing updated timestamp, creates list indexes, and includes an insert trigger so older binaries writing to a migrated database seed recency without causing later mutations to advance it. Generic metadata upserts preserve existing recency values. Turn-start updates use a dedicated monotonic touch, and process-local allocation keeps millisecond cursor values unique. State DB list, search, read, filtered-list repair, rollout fallback propagation, and app-server conversions all carry the new field. ## API `Thread` responses include: ```ts recencyAt?: number ``` `thread/list` and `thread/search` accept: ```json { "sortKey": "recency_at" } ``` Generated TypeScript and JSON schemas are included. ## Validation - `just test -p codex-state` — 146 passed - `just test -p codex-rollout` — 69 passed - `just test -p codex-thread-store` — 81 passed - `just test -p codex-app-server-protocol` — 231 passed - Focused app-server list ordering, response mapping, archive/unarchive, and resume lifecycle tests passed - Scoped `just fix` for state, rollout, thread-store, app-server-protocol, and app-server - `just fmt` - `git diff --check` - Independent correctness, simplicity, elegance, security, and test-quality reviews; actionable ordering, lifecycle, query-projection, and timestamp-uniqueness findings were addressed
Jeremy Rose ·
2026-06-16 17:06:22 -07:00 -
PAC 1 - Add system proxy feature config surface (#26706)
## Summary Introduces the default-off `respect_system_proxy` feature flag used to gate first-class system PAC/proxy support for Codex-owned native clients. With the feature disabled or absent, behavior remains unchanged. This PR establishes the configuration and managed-requirement surface; proxy discovery and request routing are implemented by follow-up PRs. ## Configuration User configuration uses the standard boolean feature form: ```toml [features] respect_system_proxy = true ``` Managed feature requirements use the corresponding boolean key. The effective runtime configuration is exposed as a boolean and defaults to `false`. ## Implementation - Registers `respect_system_proxy` as an under-development, default-off feature. - Resolves user configuration and managed feature requirements into `Config.respect_system_proxy`. - Provides bootstrap resolution for startup paths that must evaluate the feature before full configuration loading completes. - Uses the standard feature CLI and config-editing behavior. - Excludes `features.respect_system_proxy` from project-local configuration. - Updates the generated configuration schema. ## End-user behavior - No networking behavior changes when the feature is absent or disabled. - Enabling the feature makes the boolean available to the native proxy-routing implementation in follow-up PRs. - Repository-local configuration cannot enable the feature. ## Test coverage Covers scalar configuration and CLI override resolution, managed requirement constraints, bootstrap resolution, and project-local filtering.
canvrno-oai ·
2026-06-16 16:54:37 -07:00 -
[codex] [4/4] Simplify recommended plugin install schema (#28403)
## Summary - Simplify recommendation-context `request_plugin_install` arguments to `plugin_id` and `suggest_reason`. - Derive plugin type and install action from the matched candidate while preserving Codex-owned elicitation metadata. - Keep the legacy list-backed schema unchanged and accept resumed calls that still use `tool_id`. ## Stack - #28399 - #28400 - #27704 - This PR ## Validation - `just test -p codex-tools -p codex-core request_plugin_install` (25 passed) - `just fix -p codex-tools -p codex-core` - `just fmt` - `git diff --check`
Alex Daley ·
2026-06-16 23:44:42 +00:00 -
core: render remote environment cwd natively (#28152)
## Why Model-visible `<environment_context>` should match the environment of the executor, not of the app server. Stacked on #28146. ## What - Keep selected environment cwd values as `PathUri` while building environment context. - Render cwd text using the path convention represented by the URI, with the canonical URI as a fallback. - Preserve compatibility with legacy `TurnContextItem.cwd` values when reconstructing and diffing context. - Extend the Wine-backed remote Windows test to assert that the model sees `powershell` and `C:\windows`.
Adam Perry @ OpenAI ·
2026-06-16 16:17:47 -07:00 -
[codex] [3/4] Activate endpoint plugin recommendations (#27704)
Summary\n- Await endpoint recommendation selection while constructing each authenticated turn, removing the first-turn cache race.\n- Snapshot and filter endpoint candidates once per turn, then use that same set for the bounded contextual user fragment, tool exposure, and exact install validation.\n- Keep recommendation selection ephemeral: do not persist recommendation state in or gate resumed threads on prior context.\n- Hide the legacy list tool in endpoint mode and preserve legacy discovery unchanged when the endpoint is disabled or unavailable.\n- Keep remote plugin and connector app identities out of model-visible context and attach them only to Codex-owned elicitation metadata.\n\nStack\n- 3/4, based on #28400.\n- Endpoint client and cache: #28399.\n- Generalized suggestion presentation: #28400.\n- Install-schema follow-up: #28403.\n\nValidation\n- \n- \n- \n- \n- Full : 2,649 passed and 88 environment-dependent tests failed because this sandbox cannot write , nest Seatbelt, or locate auxiliary test binaries.
Alex Daley ·
2026-06-16 23:04:07 +00:00 -
[codex] [2/4] Generalize plugin suggestion presentation (#28400)
Summary - Add list-backed and developer-context presentations for plugin suggestion candidates. - Let tool planning, install validation, and request-tool copy follow the selected presentation. - Keep every production caller on the existing list-backed presentation, preserving the current list tool, request schema, connector behavior, and model-visible copy. - Leave developer-context presentation latent until the final PR in the stack. Stack - 2/3, based on #28399. - Follow-up: #27704 activates endpoint recommendations. Validation - `just test -p codex-core request_plugin_install` - `just test -p codex-core spec_plan` - `just fix -p codex-core` - `just fmt` - `git diff --check`
Alex Daley ·
2026-06-16 22:44:10 +00:00 -
app-server: preserve target-native environment cwd (#28146)
## Why app-server may run on a different OS from the selected exec-server environment. Parsing that environment’s cwd with the Codex host’s path rules prevents thread startup. ## What Carry environment cwd values as `LegacyAppPathString` at the app-server boundary and `PathUri` internally. Existing tool-call schemas and relative-path behavior stay host-native; remaining local-only consumers convert explicitly and leave follow-up TODOs. The Wine integration test verifies app-server can start a thread and complete an ordinary turn with a Windows environment cwd from Linux. ## Validation - `bazel test //codex-rs/core/tests/remote_env_windows:smoke-test --test_output=errors` - focused app-server environment-selection and protocol schema tests - scoped Clippy for `codex-core` and `codex-app-server-protocol`
Adam Perry @ OpenAI ·
2026-06-16 21:42:28 +00:00 -
[codex] Route MCP file uploads through environment filesystem (#27923)
## Why Codex Apps tools can mark arguments with `openai/fileParams`, but the execution path resolved and opened those files directly on the host. That bypassed the selected turn environment and prevented annotated file arguments from working with remote environments. ## What changed - resolve annotated file arguments against the primary turn environment - read file metadata and contents through that environment's sandboxed `ExecutorFileSystem` - reject files over the 512 MiB limit from metadata before reading or transferring them - retain the buffered upload-size check as defense in depth - make the OpenAI upload API accept a filename and buffered contents instead of owning local filesystem access - describe the model-visible argument as a path in the primary environment This builds on #27927, which added `size` to internal filesystem metadata. ## Testing - `just test -p codex-api upload_openai_file_returns_canonical_uri` - `just test -p codex-mcp tool_with_model_visible_input_schema_masks_file_params` - `just test -p codex-core mcp_openai_file` - `just test -p codex-core codex_apps_file_params_upload_environment_files_before_mcp_tool_call`
pakrym-oai ·
2026-06-16 11:27:46 -07:00 -
[codex] Warn clearly when code mode output is truncated (#28467)
## Summary - make `formatted_truncate_text` prepend `Warning: truncated output (original token count: N)` above the existing `Total output lines` header - update direct formatter, unified-exec, user-shell, and code-mode expectations - add core unit coverage that runs in Bazel without requiring the skipped V8-backed code-mode integration suite ## Validation - `cargo test -p codex-utils-output-truncation -- --nocapture` (17 passed) - `cargo test -p codex-core --lib truncated_text_output_starts_with_warning -- --nocapture` - `cargo test -p codex-core --test all clamps_model_requested_max_output_tokens_to_policy -- --nocapture` (2 passed) - `cargo test -p codex-core --test all unified_exec_formats_large_output_summary -- --nocapture` - `cargo test -p codex-core --test all user_shell_command_output_is_truncated_in_history -- --nocapture` - Bazel CI exercises the shared formatter and downstream integration expectations
Ahmed Ibrahim ·
2026-06-16 10:37:06 -07:00 -
[codex] exec-server: stream files in chunks (#28354)
## Why `fs/readFile` buffers the entire file in one response, which makes large remote reads expensive and prevents callers from applying backpressure. We need an opt-in streaming path with bounded block sizes while preserving the existing single-call API for small and sandboxed reads. ## What changed - Add `ExecServerClient::stream`, returning a named `FileReadStream` that implements `futures::Stream` and yields immutable 1 MiB byte blocks. - Add internal `fs/open`, `fs/readBlock`, and `fs/close` RPCs. `fs/readBlock` accepts an explicit offset and length. - Keep unsandboxed files open between block reads, cap open handles per connection, and clean them up on EOF, error, stream drop, explicit close, or connection shutdown. - Reject platform-sandboxed streaming opens instead of turning the one-shot sandbox helper into a persistent server. Existing `fs/readFile` behavior is unchanged. ## Testing - `just test -p codex-exec-server` - Integration coverage for 1 MiB chunking, exact block-boundary EOF, sandbox rejection, and continued reads from the opened file after path replacement. - Handle-manager coverage for non-sequential offsets, variable block lengths, the 128-handle limit, and capacity release after close.
pakrym-oai ·
2026-06-16 09:50:55 -07:00 -
core: surface terminal subagent errors to parent agents (#28375)
## Why When a subagent exhausts its retries, it emits an `Error`, but the generic task lifecycle then emits `TurnComplete(None)`. That completion used to overwrite the subagent's `Errored` status with `Completed(None)`, so the parent received an empty completion notification. This made a failed child look indistinguishable from a child that completed without an answer. In unattended or long-running multi-agent work, the root could silently continue without knowing that delegated work failed or how to restart it. ## Behavior Before, a terminal stream failure was reduced to an empty completion: ```text <subagent_notification> {"agent_path":"/root/worker","status":{"completed":null}} </subagent_notification> ``` Now the parent receives the actual terminal error, bounded to 1,000 tokens, together with an actionable recovery hint: ```text <subagent_notification> { "agent_path": "/root/worker", "status": { "errored": "stream disconnected before completion: stream closed before response.completed" }, "next_action": "This agent's turn failed. If you still need this agent, use `followup_task` to give it another task." } </subagent_notification> ``` The notification remains queue-only: it does not wake the root or replay the failed request. The root sees it at the next sampling boundary and can use `followup_task` to start a new turn for that agent. ## What changed - Added terminal-error precedence to the [agent status reducer](https://github.com/openai/codex/blob/e95fcfe2bb6a02f1a75650afa20048859f556511/codex-rs/core/src/agent/status.rs#L23-L34), so a closing `TurnComplete` cannot erase an immediately preceding `Errored` status. - Made MultiAgentV2 completion forwarding use the retained session status instead of re-deriving `Completed(None)` from the final event. - Extended the [subagent notification fragment](https://github.com/openai/codex/blob/e95fcfe2bb6a02f1a75650afa20048859f556511/codex-rs/core/src/context/subagent_notification.rs#L6-L60) with a `next_action` for terminal errors and a hard cap on model-visible error text. - Kept successful completions and interrupted turns unchanged. ## Verification - Added a status-reducer test proving that `Errored` survives the trailing `TurnComplete`. - Added an integration test that exhausts a subagent's stream retries and verifies the exact `agent_message` delivered to the parent, including the error and `followup_task` guidance. - Re-ran the existing successful-completion and interrupted-turn notification tests.jif ·
2026-06-16 14:34:54 +02:00 -
feat: render typed envelopes for multi-agent v2 messages (#28368)
## Why Multi-agent v2 messages need a consistent, model-visible envelope that identifies what kind of interaction occurred, who sent it, and which agent it targets. Previously, encrypted deliveries exposed only `encrypted_content`, while child completion used the legacy `<subagent_notification>` shape. That meant the client could not consistently present `NEW_TASK`, `MESSAGE`, and `FINAL_ANSWER` using the same format. This change adds the routing envelope as plaintext while keeping task and message payloads encrypted. No new Responses API field is required: an encrypted delivery is represented as an `input_text` header immediately followed by its existing `encrypted_content` item. Every envelope now follows this shape: ```text Message Type: <NEW_TASK | MESSAGE | FINAL_ANSWER> Task name: <recipient agent path> Sender: <author agent path> Payload: <message payload> ``` ## Message types ### `NEW_TASK` `NEW_TASK` is used when the recipient should begin a new turn, including an initial `spawn_agent` task and a later `followup_task`. For a root agent spawning `/root/worker`, the request contains a plaintext envelope followed by the encrypted task: ```json { "type": "agent_message", "author": "/root", "recipient": "/root/worker", "content": [ { "type": "input_text", "text": "Message Type: NEW_TASK\nTask name: /root/worker\nSender: /root\nPayload:\n" }, { "type": "encrypted_content", "encrypted_content": "<encrypted task payload>" } ] } ``` Conceptually, the model receives: ```text Message Type: NEW_TASK Task name: /root/worker Sender: /root Payload: Review the authentication changes and report any regressions. ``` ### `MESSAGE` `MESSAGE` is used for a queued `send_message` delivery. It communicates with an existing agent without starting a new turn. For `/root/worker` reporting progress to the root agent, the request contains: ```json { "type": "agent_message", "author": "/root/worker", "recipient": "/root", "content": [ { "type": "input_text", "text": "Message Type: MESSAGE\nTask name: /root\nSender: /root/worker\nPayload:\n" }, { "type": "encrypted_content", "encrypted_content": "<encrypted message payload>" } ] } ``` Conceptually, the model receives: ```text Message Type: MESSAGE Task name: /root Sender: /root/worker Payload: The protocol tests pass; I am checking the resume path now. ``` ### `FINAL_ANSWER` `FINAL_ANSWER` is emitted when a child agent reaches a terminal state and reports its result to its parent. Completion payloads are already available locally, so the complete envelope is represented as plaintext rather than as a plaintext header plus encrypted content. For `/root/worker` completing work for the root agent, the request contains: ```json { "type": "agent_message", "author": "/root/worker", "recipient": "/root", "content": [ { "type": "input_text", "text": "Message Type: FINAL_ANSWER\nTask name: /root\nSender: /root/worker\nPayload:\nNo regressions found." } ] } ``` The model-visible form is: ```text Message Type: FINAL_ANSWER Task name: /root Sender: /root/worker Payload: No regressions found. ``` Errored, shut down, and missing agents also use `FINAL_ANSWER`, with a terminal-status description in the payload. ## What changed - Render `NEW_TASK` or `MESSAGE` in `InterAgentCommunication::to_model_input_item`, based on whether the encrypted delivery starts a turn. - Replace the multi-agent v2 `<subagent_notification>` completion payload with a model-visible `FINAL_ANSWER` envelope. - Document `Task name`, `Sender`, and `Payload` consistently in the multi-agent developer instructions. - Prevent local-only history projections from treating an encrypted message's plaintext header as the complete assistant message. - Preserve rollout-trace interaction edges when an agent message contains both plaintext and encrypted content. Legacy multi-agent behavior remains unchanged. ## Verification - `just test -p codex-protocol` - `just test -p codex-rollout-trace` - `just test -p codex-web-search-extension` - `just test -p codex-core encrypted_multi_agent_v2_spawn_sends_agent_message_to_child` - `just test -p codex-core plaintext_multi_agent_v2_completion_sends_agent_message` - `just test -p codex-core multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn` - `just test -p codex-core multi_agent_v2_completion_queues_message_for_direct_parent`jif ·
2026-06-16 11:46:59 +02:00 -
[codex] Use local environment for user shell commands (#28163)
## Why User shell commands still read the legacy turn cwd and session shell even though execution context is now owned by selected turn environments. App-server also defines `thread/shellCommand` as a local-host escape hatch, so it must use an available local environment even when a remote environment is primary. ## What changed - Add `ResolvedTurnEnvironments::local()` to find the selected local environment. - Resolve the user shell command cwd and shell from that local `TurnEnvironment`. - Emit the standard `shell is unavailable in this session` error when no selected local environment or resolved local shell is available. - Add an integration test covering `/shell` without a local environment. ## Test plan - `just test -p codex-core user_shell_command_without_local_environment_emits_error`
pakrym-oai ·
2026-06-16 04:55:20 +00:00 -
[codex] Add interruptible sleep tool (#28429)
## Why Models sometimes need to pause briefly while waiting for external work, but using a shell command for that delay ties the wait to a process and does not naturally resume when new turn input arrives. ## What changed - add a built-in `sleep` tool behind the under-development `sleep_tool` feature - accept a bounded `duration_ms` argument, matching the millisecond convention used by unified exec - end the sleep early when either steered user input or mailbox input arrives - include elapsed wall-clock time in completed and interrupted outputs - emit a dedicated core `SleepItem` through `item/started` and `item/completed` - expose the sleep item as app-server v2 `ThreadItem::Sleep` and retain it in reconstructed thread history - regenerate the configuration schema for the new feature flag - regenerate app-server JSON and TypeScript schema fixtures ## Test plan - `just test -p codex-core sleep_tool_follows_feature_gate` - `just test -p codex-core any_new_input_interrupts_sleep` - `just test -p codex-app-server-protocol` - `just test -p codex-app-server sleep_emits_started_and_completed_items`
pakrym-oai ·
2026-06-15 21:39:21 -07:00 -
[codex] Bind shell snapshots to retained thread environments (#28421)
## Why Shell snapshots are currently session-scoped even though shell and cwd are properties of a selected turn environment. That makes snapshot refresh depend on separate session-cwd plumbing, prevents retained environments from retaining their snapshot work, and can make snapshot construction use a different shell than command execution. This follows #27955 by making the retained thread-environment service own environment snapshot lifecycles. Session configuration remains the requested selection state, while `ThreadEnvironments` remains the source of successfully resolved environments. ## What changed - Configure the shell-snapshot builder before initial environment resolution. - Start each local environment snapshot task when its `TurnEnvironment` is built and retain that shared task while environment ID and cwd still match. - Inherit retained environment snapshots into spawned child threads. - Carry the selected `TurnEnvironment` through shell runtimes so snapshot construction and command execution use the same environment-specific shell and cwd. - Load project instructions and warm plugins/skills after initial environment resolution. - Continue decoding invalid UTF-8 instruction files lossily without emitting a startup warning. - Keep requested selections in `SessionConfiguration`; failed or duplicate resolutions only affect the resolved environment snapshot. ## Validation - `cargo check -p codex-core --tests` - `just test -p codex-home instructions` (6 passed) - Focused environment, instruction, shell-snapshot, and user-shell tests (84 passed) - Focused shell-snapshot, user-shell, and unified-exec tests (126 passed; two event-timing tests passed on retry)
pakrym-oai ·
2026-06-15 20:10:53 -07:00 -
Add a toggle for realtime startup context (#28405)
## Summary - Add `includeStartupContext` to realtime start requests so callers can explicitly skip Codex startup context while keeping the backend prompt - Thread the new flag through protocol types, request processing, and realtime session config - Update app-server docs and coverage for the new default and opt-out behavior ## Testing - Added protocol serialization coverage for `includeStartupContext` - Added realtime integration coverage for starting a session with startup context disabled
guinness-oai ·
2026-06-15 17:14:22 -07:00 -
[codex] Fix missing response item metadata in tests (#28415)
Summary - Add the two missing `metadata: None` initializers after #28355 made response-item metadata required. - Restore test compilation for `codex-core` and `codex-api` on main. Validation - `git diff --check` - `just fmt` (Rust formatting passed; unrelated Python formatter steps could not use the sandboxed shared `uv` cache) - Focused crate tests are running after PR creation.
Alex Daley ·
2026-06-16 00:08:39 +00:00 -
Use PathUri in filesystem permission paths for exec-server (#28165)
## Why Progress towards letting app-server and exec-server run on different platforms, specifically for sandbox configuration. ## What - Make the filesystem path containment hierarchy generic, defaulting to `AbsolutePathBuf` for now. - Have clients specify `AbsolutePathBuf` or `PathUri` directly where needed. - Use `PathUri` throughout exec-server filesystem protocol and trait boundaries. - Implement `From` for conversion to path URIs and `TryFrom` for fallible conversion to absolute paths through the generic type hierarchy.
Adam Perry @ OpenAI ·
2026-06-15 23:55:23 +00:00 -
Add realtime speech append control (#27917)
## Why Realtime voice harness tuning needs app-side control over what backend Codex text is spoken. Backend orchestrator text is written for a reading UI, so automatically speaking every preamble, progress update, or final assistant message can make the realtime voice model too chatty. For experimentation, clients need two simple controls: keep app/client text-item injection on the existing item-create path, and add an explicit speakable path that app code can call only when it wants realtime to speak. Automatic Codex output also needs an opt-in way to switch from the protocol's default speakable path to regular realtime items, with a caller-provided prefix so prompt wording can be tuned outside core. The default remains unchanged: if a client omits the new start fields and never calls `appendSpeech`, automatic backend output continues down the existing speakable path for the selected realtime protocol. ## What Changed - Adds experimental `thread/realtime/appendSpeech` for app-provided speakable text. - Keeps existing `thread/realtime/appendText` as the item-create API for app-provided realtime text items. - Adds `codexResponsesAsItems` / `codex_responses_as_items` on `thread/realtime/start` to send automatic Codex responses with `conversation.item.create` instead of the protocol's default speakable output path. - Adds `codexResponseItemPrefix` / `codex_response_item_prefix` so clients can prepend experiment instructions to those automatic Codex response items. - Keeps literal `conversation.handoff.append` routing scoped to the v1 speakable path; v2 default speech uses its item/function-output plus `response.create` behavior. - Removes the earlier public silent-context API and hardcoded silent-context prefix. - Updates realtime tests to cover default automatic speakable behavior, opt-in automatic item-create behavior, and explicit `appendSpeech` behavior. ## Validation - `cargo check -p codex-core -p codex-app-server -p codex-api` - `just test -p codex-app-server realtime_conversation` - `just test -p codex-core realtime_conversation` (50/51 passed in the filtered parallel run; the lone failure passed when rerun in isolation) - `just test -p codex-core conversation_mirrors_assistant_message_text_to_realtime_handoff` - `just test -p codex-api e2e_connect_and_exchange_events_against_mock_ws_server` - `just fix -p codex-core` - `just fix -p codex-app-server` - `cargo build -p codex-cli`
guinness-oai ·
2026-06-15 16:15:58 -07:00 -
[codex] retain resolved environments across turns (#27955)
## Why Selected execution environments are thread-scoped resources, but startup and turn construction repeatedly resolved their IDs and working directories. That discarded existing environment handles and shell metadata even when a selection had not changed. Session configuration updates also need to affect future turns without changing the resolved environment set already captured by a running turn. ## What changed - Create a `ThreadEnvironments` service inside `Codex` from the spawned `EnvironmentManager` and raw environment selections, then store it on `SessionServices`. - Split service construction from `update_selections`, allowing session configuration updates to mutate the resolved set in place. - Retain an existing `TurnEnvironment` when its environment ID and working directory match; resolve only added or changed selections and remove selections that are no longer present. - Normalize duplicate IDs by keeping the first selection and skip individual selections that fail to resolve instead of rejecting the entire update. - Give each `TurnContext` a cloned `TurnEnvironmentSnapshot`, so later session configuration updates affect future turns without rewriting an active turn. - Reuse the service-owned environment manager and resolved snapshot for startup work, MCP initialization, and child-thread spawning instead of flowing resolved environments through spawn arguments. ## Test plan - `cargo check -p codex-core --tests` - `just test -p codex-core environment_selection` - `just test -p codex-core turn_environments` - `just test -p codex-core session_update_settings_does_not_rewrite_sticky_environment_cwds` - `just test -p codex-core default_turn_does_not_overlay_legacy_fallback_cwd_onto_stored_thread_environments`
pakrym-oai ·
2026-06-15 16:15:07 -07:00 -
[codex] Reuse Apps policy evaluation across MCP tool exposure (#27813)
## Summary - move `AppToolPolicyEvaluator` and the Apps config/requirements policy logic from `codex-core` into `codex-connectors` - resolve one immutable policy snapshot per exposure build and reuse it across every Codex Apps MCP tool - keep core as a thin adapter from MCP metadata to connector-owned policy input while preserving the call-time defense-in-depth check ## Why `build_mcp_tool_exposure` evaluates every Codex Apps tool on each sampling request. The old path rebuilt effective Apps configuration for every tool, and the policy implementation lived in the already-large core crate even though it is connector-specific. The connector-owned evaluator keeps the expensive config merge/decode out of the loop and gives core only the effective policy result it needs. ## Performance With the real 557-tool Apps corpus, `build_mcp_tool_exposure` measured 3.74 ms and 3.33 ms after the extraction (3.54 ms mean). The original path measured 807 ms mean, so the final result retains the 99.6% reduction. ## Validation - `cargo check -p codex-connectors -p codex-core` - `just test -p codex-connectors` — 15 passed - `just test -p codex-core --lib connectors` — 35 passed - `just test -p codex-core --lib mcp_tool_exposure` — 5 passed - `just test -p codex-core --lib mcp_tool_call` — 72 passed - `just bazel-lock-update` - `just bazel-lock-check` - `just fix -p codex-connectors` - `just fix -p codex-core` - `just fmt`
Matthew Zeng ·
2026-06-15 15:24:33 -07:00 -
Respect blocking PostToolUse hooks in code mode (#28365)
## Summary Make blocking hook behavior reliable for tools invoked from code mode. Previously, a `PostToolUse` hook could block a completed tool result, but code mode would still return the original typed result to JavaScript. The hook appeared blocked in hook telemetry while the running script continued with the result. This change: - rejects the nested JavaScript tool promise when `PostToolUse` blocks - normalizes `decision: "block"` and exit code 2 to the same blocking behavior - surfaces the hook feedback as the rejected promise's error - adds end-to-end coverage for the relevant PreToolUse and PostToolUse interactions ## Hook semantics in code mode | Hook behavior | Code-mode result | |---|---| | PreToolUse block | Reject the promise before the tool executes | | PreToolUse `updatedInput` | Execute the rewritten invocation and return its result | | PostToolUse `decision: "block"` | Execute the tool, then reject the promise with the hook reason | | PostToolUse exit code 2 | Same behavior as `decision: "block"` | | PostToolUse `continue: false` | Preserve the existing feedback-only behavior; do not reject the promise | ## Test coverage Added or strengthened end-to-end coverage proving that: - a PreToolUse block rejects the JavaScript promise before execution - a PreToolUse input rewrite executes only the rewritten command - JavaScript receives the rewritten command's result - PostToolUse `decision: "block"` rejects after the command executes - PostToolUse exit code 2 has the same behavior - the hook observes the original completed tool response - the blocked original result does not reach JavaScript - existing direct-mode replacement behavior remains intact - `continue: false` without a reason produces deterministic fallback feedback
Abhinav ·
2026-06-15 15:12:26 -07:00 -
[codex] Add created-by-me remote plugin marketplace (#28203)
## Summary - add the `created-by-me-remote` marketplace backed by paginated `scope=USER` plugin directory and installed-plugin requests - include USER plugins in installed-plugin caching, bundle sync, and stale-cache cleanup without client-side discoverability filtering - expose the marketplace through app-server v2 and regenerate the protocol schemas ## Testing - `cargo build -p codex-app-server --bin codex-app-server` - production-auth `plugin/list` smoke test for `created-by-me-remote` (returned the expected USER plugin as installed and enabled) - `just test -p codex-core-plugins` (221 passed) - `just test -p codex-app-server-protocol` (231 passed) - `just test -p codex-app-server suite::v2::plugin_list::` (37 passed) - `just fix -p codex-core-plugins -p codex-app-server-protocol -p codex-app-server` - `just fmt`
Eric Ning ·
2026-06-15 22:07:07 +00:00 -
feat(core): add metadata field to ResponseItem (#28355)
## Description This PR adds an optional `metadata` field to `ResponseItem` for Responses API calls. Only mechanical plumbing, no actual values populated and sent yet. Turns out just adding a new field to `ResponseItem` has quite a large blast radius already. This change is backwards compatible because `metadata` is optional and omitted when absent, so existing response items and rollout history without it still deserialize and requests that do not set it keep the same wire shape. For provider compatibility, we strip out `metadata` before non-OpenAI Responses requests so Azure and AWS Bedrock never see this field. My followup PR here will actually make use of it to start storing and passing along `turn_id`: https://github.com/openai/codex/pull/28360 ## What changed - Added `ResponseItemMetadata` with optional `turn_id`, plus optional `metadata` on Responses API item variants and inter-agent communication. - Preserved item metadata through response-item rewrites such as truncation, missing tool-output synthesis, compaction history rebuilding, visible-history conversion, rollout/resume, and generated app-server schemas/types. - Strip item metadata from non-OpenAI Responses requests while preserving it for OpenAI-shaped requests. - Updated the mechanical fixture/test construction churn required by the new optional field.
Owen Lin ·
2026-06-15 15:05:28 -07:00 -
core: cache the tool search handler per session (#27258)
## Why Tool router construction rebuilds the deferred-tool BM25 index during session initialization and before each sampling continuation, even when the searchable tool metadata is unchanged. Local profiling measured `append_tool_search_executor` at roughly 113 ms per continuation, making repeated index construction the largest measured router-building cost. ## What changed - Add a session-scoped `ToolSearchHandlerCache` so continuations and user turns can reuse the existing handler. - Key reuse on the complete ordered `Vec<ToolSearchInfo>`, rebuilding when searchable text, loadable tool specs, source metadata, or ordering changes. - Build handlers outside the cache lock and recheck before publishing them, avoiding holding the mutex during index construction. ## Verification - `cache_reuses_identical_search_infos_and_rebuilds_changed_inputs` covers exact cache reuse and invalidation when the ordered search metadata changes. - Local rollout profiling showed the initial router build populating the cache and unchanged later continuations reusing it: - uncached: 118 ms median across 14 spans from 3 rollouts - cached: 4 ms median across 12 spans from 3 rollouts
mchen-oai ·
2026-06-15 14:48:30 -07:00 -
Add hidden Windows sandbox wrapper entrypoint (#28358)
## Why This is the second PR in the Windows fs-helper sandbox stack. The fs-helper path needs a Windows sandbox launcher that has the same argv-shaped contract as macOS `sandbox-exec` and `codex-linux-sandbox`, but this PR only introduces that hidden launcher. It does not route fs-helper through it yet. The hidden launcher still needs to be policy-complete before later direct-spawn callers use it. In particular, it has to carry the same Windows sandbox policy details that the existing spawn paths already understand: proxy enforcement, read/write root overrides, and deny-read/deny-write overrides. ## What Changed - Added the hidden `codex.exe --run-as-windows-sandbox` arg1 dispatch path. - Added `windows-sandbox-rs/src/wrapper.rs`, which parses the wrapper argv, launches the requested command through the shared Windows sandbox session runner from PR1, and forwards stdio. - Added `create_windows_sandbox_command_args_for_permission_profile()` so later direct-spawn callers can build the wrapper argv consistently. - Made the wrapper argv round-trip the full Windows sandbox policy surface it needs later: workspace roots, environment, permission profile, sandbox level, private desktop, proxy enforcement, read/write root overrides, and deny-read/deny-write overrides. - Carried `proxy_enforced` through the shared Windows session request so proxy-managed executions continue to use the offline/elevated sandbox identity. - Added wrapper argument round-trip coverage for the full policy fields. ## Verification - `just test -p codex-windows-sandbox windows_wrapper_args_round_trip` - `just test -p codex-arg0` - `just test -p codex-core exec::tests::windows_` - `just fix -p codex-windows-sandbox -p codex-core -p codex-cli` Local note: the full `just fmt` command still fails on this workstation in non-Rust formatter setup (`uv` cache access denied and missing `dotslash`/buildifier), but the Rust formatter phase completed.
iceweasel-oai ·
2026-06-15 21:30:32 +00:00 -
Add Windows unified exec yield floor (#27086)
## Why The Windows `unified_exec` experiment regressed at the turn level in a way that points to premature backgrounding / extra command cycles rather than individual responses getting heavier: - `codex_local_tool_calls_per_turn` was up about 20.7%. - `codex_local_blended_tokens_per_turn` was up about 4.1%, and `codex_local_output_tokens_per_turn` was up about 4.0%. - `codex_local_response_latency_per_turn` was up about 8.3%. - The primary activity metrics also moved down: `codex_turns` about -6.6%, `codex_dau` about -1.0%, and `codex_local_hourly_active_users` about -3.0%. At the same time, the per-response metrics moved in the other direction: blended tokens per response, output tokens per response, and latency per response were all lower in test. That suggests the bad turn-level shape is largely about extra tool/model cycles, not each response being slower or more expensive on its own. Local Windows benchmarking showed the likely mechanism: shell-wrapped commands pay a large PowerShell startup/teardown tax before the actual command has much time to run. In the benchmark, the PowerShell wrapper added roughly 0.7-1.0s versus direct exec: - Windows PowerShell: about 740ms p50 / 800ms p90 overhead versus direct exec. - PowerShell 7 (`pwsh`): about 930ms p50 / 980ms p90 overhead versus direct exec. The model commonly asks for a 1s initial yield. On Windows, that can spend nearly the whole window waiting on PowerShell machinery, so otherwise-short commands are more likely to return as background sessions and require follow-up polling/tool calls. This is intentionally a temporary unlock. It gives Windows closer to the same useful post-shell command window as other platforms while we work on reducing the PowerShell tax directly, for example with persistent PowerShell workers or conservative direct-exec paths for commands that do not need shell semantics. ## What changed - Adds a Windows-only 2s floor to `unified_exec`'s initial `yield_time_ms` clamp. - Keeps larger model-requested waits unchanged, including the existing 10s default. - Keeps the existing 30s max clamp. - Leaves non-Windows behavior unchanged. - Adds platform-gated tests for both the Windows floor and the non-Windows clamp behavior. ## Verification - `just test -p codex-core unified_exec`
iceweasel-oai ·
2026-06-15 13:56:18 -07:00 -
core: let steer interrupt wait_agent (#28341)
## Why `wait_agent` can block for a long timeout while waiting for sub-agent mailbox activity. Although same-turn user steer is accepted during that tool call, the input remains pending until the wait returns, so an explicit request to change direction can appear unresponsive. ## What changed - Notify active `wait_agent` calls when user input is steered into the current turn. - Check for already-pending steer input when subscribing so input that races with tool startup is not missed. - Distinguish mailbox activity, steered input, and timeout outcomes, returning `Wait interrupted by new input.` for the steer path. - Update the `wait_agent` tool description to document the early-return behavior. ## Testing - `just test -p codex-core input_queue_` - `just test -p codex-core wait_agent` The coverage includes steer notification before and after subscription, plus an end-to-end test that verifies the interrupted wait result and steered user input are both included exactly once in the follow-up model request.
jif ·
2026-06-15 20:08:15 +02:00 -
guardian: isolate review context from skills and memories (#28285)
## Why Guardian reviews embed the parent session transcript as untrusted evidence. Skill or plugin mentions in that transcript must not be interpreted as requests to inject more instructions into the Guardian request, and memory context adds unrelated model-visible context to an approval decision. Keeping those sources out of the nested review session makes the request smaller and preserves the trust boundary around the transcript being assessed. ## What changed - Skip skill and plugin discovery when building turns for Guardian reviewer sessions. - Disable memory context and dedicated memory tools in the derived Guardian configuration. - Extend the Guardian request-layout coverage to verify that a `$skill` mention remains visible only as transcript evidence while neither the skill body nor memory context is injected. - Expand the Guardian configuration test to cover the disabled memory settings. ## Testing - Updated the Guardian review request snapshot and assertions for skill and memory isolation. - Extended the Guardian session configuration test to cover memories.
jif ·
2026-06-15 19:24:50 +02:00 -
[codex] preserve explicit environment cwd (#27995)
## Why `TurnEnvironmentSelections::new` rewrote the primary environment's explicit `cwd` to the legacy fallback cwd. For a remote-first selection, this could replace the remote working directory with a local fallback path and made the legacy cwd overlay authoritative over environment-owned state. ## What changed - Preserve every explicit environment cwd when constructing turn environment selections. - Keep `cwd`-only app-server updates compatible by rebuilding the default environment selections at the requested cwd. - Cover both explicit primary cwd preservation and cwd-only updates reaching the model-visible execution environment. ## Testing - `just test -p codex-core session_update_settings_does_not_rewrite_sticky_environment_cwds` - `just test -p codex-core environment_settings_preserve_explicit_primary_cwd` - `just test -p codex-app-server thread_settings_update_cwd_retargets_default_environment`
pakrym-oai ·
2026-06-15 17:17:34 +00:00 -
[codex] remove stale PathExt import (#28344)
## Why `main` fails dev-profile Cargo and Bazel Clippy builds because `core/src/tools/runtimes/mod_tests.rs` imports `PathExt` after its last use was removed. With warnings denied, that stale import prevents `codex-core` test targets from compiling across platforms. ## What changed Remove the unused `PathExt` import. Remaining `.abs()` calls in the module operate on `PathBuf` and continue to use `PathBufExt`. ## Validation - `just fmt` - Focused `codex-core` test compile attempted; blocked locally by disk exhaustion before compilation completed. The CI failure itself is the unused-import diagnostic this change removes.
pakrym-oai ·
2026-06-15 09:56:21 -07:00 -
avoid cloning websocket request history (#28313)
## Why WebSocket continuations only send the new part of a request. Checking whether a request could be continued was cloning the full previous request, the current request, and their input history. For long conversations or large tool lists, that meant copying several request-sized values on every continuation. ## What changed - compare the request settings by reference - check the previous input and server response as borrowed prefixes - allocate only the new input items that will be sent The reuse rules stay the same, including ignoring `client_metadata` for this check. The comparison is still `O(n)`, but it removes several `O(n)` allocations and copies. Temporary memory no longer grows by multiple full request sizes for each continuation. ## Performance Local rollout traces show continuation checks on turns around 260k input tokens. Before this change the reuse gate cloned the previous request, the current request, and the previous input history before deciding whether it could continue incrementally. After this change it borrows those structures and allocates only the incremental tail. For large continuations with a small delta, that removes roughly three request-sized copies from the hot path and reduces temporary memory from multiple full request sizes to just the new tail. ## Validation - `just test -p codex-core responses_websocket_v2_creates_with_previous_response_id_on_prefix` - `just test -p codex-core responses_websocket_v2_creates_without_previous_response_id_when_non_input_fields_change`
jif ·
2026-06-15 18:48:47 +02:00 -
avoid cloning sampling request input (#28306)
## Why Every model request cloned the full prepared input just to keep it for the legacy after-agent hook. That copy gets more expensive as the conversation grows. ## What Move the prepared input into the sampling loop and return it with the result. If the request retries, keep the first input so the hook still sees the same data as before. This removes one `O(n)` clone per sampling request, where `n` is the size of the prepared input. It saves `O(n)` copy work and `O(n)` temporary memory. No behavior change is intended. ## Performance Local rollout traces show turns reaching roughly 260k input tokens. On turns of that size, this removes the only unconditional full prepared-input clone on the happy path. That avoids one request-sized allocation/copy per sampling attempt for large conversations, and the savings scale linearly with request size. ## Testing - `just test -p codex-core continue_after_stream_error` - `just fix -p codex-core`
jif ·
2026-06-15 18:26:44 +02:00 -
linearize history output normalization (#28309)
## Why When we prepare the conversation history, every tool call needs a matching output. Before this change, we scanned the full history again for every call. In a tool-heavy conversation, that makes the work `O(items x calls)`, or `O(n^2)` in the worst case. ## What Scan the history once and collect the IDs of existing outputs. Then each call can check its ID with an expected `O(1)` lookup. The full normalization step is now expected `O(n)`. The output order and missing-output behavior stay the same. ## Performance Based on local rollout traces, one tool-heavy session reached roughly 17,050 transcript items with about 4,292 tool-call items. On a history of that shape, the old `calls x items` scan does about 73.2 million membership checks, while the new pass does about 21.3 thousand set inserts/lookups. That is roughly 3.4k times less membership work in this normalization step. ## Validation - `just test -p codex-core normalize_` (19 passed)
jif ·
2026-06-15 18:26:34 +02:00 -
[codex] simplify memory read metrics (#28164)
## Why Memory read telemetry currently reconstructs the executable shell command after a tool call finishes. That duplicates shell, login-policy, and cwd resolution owned by the tool handlers, and can diverge from the environment-specific command that unified exec actually ran. ## What changed - Expose the existing restricted shell-script parser directly for raw script text. - Parse `shell_command` and `exec_command` input into plain command argv before classifying memory reads. - Preserve all-or-nothing safe-command validation for multi-command scripts. - Remove cwd resolution, shell selection, and the unnecessary async boundary from memory read metric emission. ## Testing - `just test -p codex-shell-command` - `cargo check -p codex-core`
pakrym-oai ·
2026-06-15 08:28:02 -07:00 -
[codex] simplify shell snapshot ownership (#27756)
## Why Shell snapshot lifecycle state was split between `Shell` and `SessionServices`: `Shell` carried the receiver while session code exposed and forwarded the raw sender. That coupled shell identity to mutable snapshot state and made refresh, inheritance, and file lifetime harder to reason about. ## What changed - make each `Arc<ShellSnapshot>` represent one cwd-specific snapshot generation - store the active generation in `SessionServices` with `ArcSwapOption` - have construction start the background build and expose only a cwd-validated snapshot path - use `ShellSnapshotFile` ownership to delete snapshot files automatically - pass snapshot paths explicitly to shell runtimes instead of storing snapshot state on `Shell` - preserve inherited and in-flight generations by pinning their `Arc` while they are in use ## Test plan - `cargo check -p codex-core --lib` - `just test -p codex-core 'shell_snapshot::tests'` - `just test -p codex-core shell_command_snapshot_still_intercepts_apply_patch` - `just test -p codex-core shell_snapshot_deleted_after_shutdown_with_skills`
pakrym-oai ·
2026-06-15 08:18:13 -07:00 -
skills: hide orchestrator skills with a local executor (#28333)
## Why App-server threads without a local executor need orchestrator-owned skills from the hosted `codex_apps` MCP server. Threads with the local executor already discover installed skills from the local filesystem. After the orchestrator skill provider was enabled for every app-server thread, local-executor threads also received the hosted skill catalog and the `skills.list` and `skills.read` tools. This changed the existing local behavior and could expose a second hosted copy of a skill that was already installed locally. ## What changed - Expose the thread's selected execution environments to extensions at thread startup. - Enable orchestrator skills only when the reserved local environment is not selected. - Apply that decision consistently to hosted skill catalog discovery, explicit skill injection, and the `skills.list` and `skills.read` tools. ## Verification - The existing no-executor app-server test continues to verify hosted skill discovery, invocation, and child-resource reads. - A new app-server test verifies that local-executor threads do not receive hosted skill context or `skills.*` tools.
jif ·
2026-06-15 17:15:45 +02:00 -
Represent dynamic tools with explicit namespaces internally (#27365)
Follow-up to #27356. ## Stack note This PR changes Codex's internal dynamic-tool shape while leaving `thread/start` unchanged. App-server therefore converts the existing per-tool input into explicit functions and namespaces before passing it to core. [#27371](https://github.com/openai/codex/pull/27371) updates `thread/start` to use the same explicit shape and removes this temporary conversion. ## Why Dynamic tools repeat namespace metadata on every function. Core should keep one explicit namespace with its member tools so descriptions and membership stay consistent across sessions and runtime planning. ## What changed - Represent dynamic tools as top-level functions or explicit namespaces in protocol and session state. - Read old flat rollout metadata and write the canonical hierarchy. - Flatten namespace members only when registering callable tools. - Keep `thread/start.dynamicTools` flat for now and normalize it at the app-server boundary. New builds can read old rollout metadata. Older builds cannot read newly written hierarchical metadata. ## Test plan - `just test -p codex-app-server thread_start_normalizes_legacy_dynamic_tools_into_model_request` - `just test -p codex-protocol session_meta_normalizes_legacy_dynamic_tools` - `just test -p codex-core resume_restores_dynamic_tools_from_rollout_with_sqlite_enabled` - `just test -p codex-core tool_search_returns_deferred_dynamic_tool_and_routes_follow_up_call` - `just test -p codex-core code_mode_can_call_hidden_dynamic_tools` - `just test -p codex-tools`
sayan-oai ·
2026-06-15 08:06:14 -07:00