Commit Graph
1006 Commits
Author SHA1 Message Date
Martin Au-Yeung 800715d201 Remove template IDs from MCP tool call metadata (#33467)
## What changed

- Remove `template_id` from MCP tool call items and lifecycle events.
- Remove `templateId` from app-server `McpToolCallAppContext` responses and generated schemas.
- Update protocol conversions, documentation, and existing test expectations for the revised metadata shape.

GitOrigin-RevId: f2b1304eadff661eec3966673ea71206b1542b98
2026-07-16 01:23:52 +00:00
rka-oai 768330dd6c Add a fallback phase before automatic context rollover (#33255)
## Why

Token-budget sessions need a final opportunity to preserve important state before the current context is compacted.

## What changed

- When `auto_compact_fallback_prompt` is configured, reserve `auto_compact_fallback_buffer_tokens` beyond the base auto-compaction limit.
- At the base limit, inject the fallback prompt once as a developer message while keeping the normal tool surface available. Continue reporting zero base-window tokens during this reserve.
- Roll over when the reserve or full model context is exhausted, and skip the fallback when a new context was already requested.

## Testing

Added coverage for using the fallback reserve, rolling over after it is exhausted, and bypassing the fallback for an explicit `new_context` request.

GitOrigin-RevId: 32983ecadc5cb4927e15ecd7b1e896cb52a9ad3b
2026-07-15 05:45:43 +00:00
pakrym-oai e4711f2a3b Separate session state from session I/O (#33209)
## What changed

- Replace the combined `Codex` wrapper with an `Arc<Session>` and a dedicated
  `SessionIo` handle for submissions, events, status, and loop termination.
- Make `Session::spawn` return the session and I/O handle separately, and have
  `CodexThread` own both.
- Update thread management, delegated sessions, guardian reviews, and agent
  control to use the appropriate session or I/O interface.

GitOrigin-RevId: 8523bad7e7366e2969fd0cc3849b4247b141427a
2026-07-15 02:16:53 +00:00
Adam Perry @ OpenAI 72b41c55fb Separate exec permission paths from core models (#33200)
## Why

Core filesystem permission models operate on native absolute paths, while exec
sandbox contexts must serialize paths as portable URIs.

## What changed

- Make the core filesystem permission and profile types concrete over
  `AbsolutePathBuf` instead of generic over their path representation.
- Add exec-specific permission types that convert native permission paths to
  `PathUri` values at the sandbox protocol boundary.
- Replace the legacy read/write-roots tuple with a named
  `LegacyReadWriteRoots` struct.

## Testing

- Add coverage that exec sandbox permission paths serialize as URIs and round
  trip through the filesystem protocol.

GitOrigin-RevId: a0ef5f8aba9bbfdf00a00fcc4f199314836bc85d
2026-07-15 01:31:40 +00:00
iceweasel-oai a2fb3f048d Document the Windows exec yield time range (#33167)
## What changed

Document that `exec_command.yield_time_ms` has an effective range of
2,000–30,000 ms on Windows, and update the tool specification test to match.

GitOrigin-RevId: aa20bbb2ad82d162d29d93f3bfbe1b970445f44e
2026-07-14 21:11:32 +00:00
pakrym-oai 5d325ba223 Move sleep items to the extension-owned lifecycle path (#33159)
## What changed

- Define `SleepItem` in `codex-extension-items` and carry `clock.sleep` events through `TurnItem::Extension`.
- Preserve sleep persistence, thread-history reconstruction, and the app-server's `type: "sleep"` schema while reusing the extension-owned type.

## Testing

- Add serialization coverage for the `clock.sleep` extension wire shape and its protocol wrapper.
- Update sleep lifecycle and thread-history tests to exercise the extension-owned item.

GitOrigin-RevId: 34bb33ed9b90a09bf4744aafdb56e019c717a168
2026-07-14 21:01:54 +00:00
iceweasel-oai 4da39dbea7 Clarify exec yield timing on Windows (#33150)
## Why

The generic `yield_time_ms` description does not explain the Windows-specific
initial wait behavior or when callers should choose a shorter value.

## What changed

- Describe `yield_time_ms` on Windows as the maximum wait before a running
  command returns a session ID, while commands that finish sooner still return
  immediately.
- Recommend the 10-second default for ordinary commands and shorter waits for
  intentionally long-lived or interactive processes.
- Keep the existing parameter description on other platforms.

## Testing

- Update the expected `exec_command` tool schema for both platform variants.

GitOrigin-RevId: 32f90b3a56604fcf1734cc81ba7ab2f0bec41643
2026-07-14 20:44:07 +00:00
jif 1447cee36b Build MCP tool runtimes before router planning (#33149)
## What changed

- Convert filtered MCP tool metadata into `CoreToolRuntime` instances before constructing the tool router.
- Pass those runtimes through the shared tool-planning path instead of maintaining separate direct and deferred MCP tool lists.
- Preserve MCP visibility, app policy filtering, and direct versus deferred exposure behavior.

GitOrigin-RevId: 67f7fbeecc2992318c859e038cd97938833911db
2026-07-14 20:36:29 +00:00
Bryan Ashley 8604689ec5 Allow injecting the Codex Apps tools cache (#33113)
## What changed

- Accept a caller-provided `CodexAppsToolsCache` when constructing a `ThreadManager` and pass it through to the MCP manager.
- Add `ConnectorRuntimeManager::new_without_cache()` for an in-memory runtime that neither loads nor persists connector state on disk.
- Re-export `CodexAppsToolsCache` from `codex-core` and `codex-core-api` for embedders.

## Testing

- Verify that a cache-disabled connector runtime ignores existing disk state and publishes live tools without creating cache files.

GitOrigin-RevId: f52f4f27c425a8d84ad0d0987b30a6fc3c14d702
2026-07-14 17:10:04 +00:00
jif 64c0e2fa1b Remove task messages from list_agents output (#33030)
## What changed

- Return only each live agent's name and status from `list_agents`.
- Stop tracking the most recent task message in agent metadata.

GitOrigin-RevId: 91836fe8efad7ea6b7305f0b409081ec77419cfd
2026-07-14 10:22:04 +00:00
pakrym-oai 393f64565a Scope runtime workspace roots to execution environments (#32952)
## Why

Multi-environment turns can run against different filesystems, so a single
thread-wide workspace-root list cannot accurately describe every selected
environment.

## What changed

- Add optional `runtimeWorkspaceRoots` to each app-server environment selection.
  Omitted roots default to that environment's `cwd`, while an empty list selects
  no roots.
- Carry environment-native roots through turn selection, model-visible context,
  permission materialization, and tool sandboxing.
- Keep the top-level `runtimeWorkspaceRoots` field as a compatibility input when
  constructing default environment selections; explicit selections use their
  own roots.

## Testing

- Cover thread and turn API defaults, overrides, empty roots, and schema
  round-tripping.
- Verify foreign roots remain model-visible and remote execution applies the
  target environment's roots before sandbox selection.

GitOrigin-RevId: c6e7a62883c45c676c153055f46a55ee15a323a4
2026-07-14 04:41:08 +00:00
Matthew Zeng b019a5577c Tighten recommended plugin install suggestions (#32949)
## What changed

- Limit `request_plugin_install` guidance to explicitly requested plugins after tool search has been exhausted.
- Exclude adjacent capabilities, broad recommendations, and plugins that only seem potentially useful.
- Clarify that `plugin_id` is the parenthesized ID from `<recommended_plugins>` and prohibit parallel tool calls.
- Keep the recommendation context focused on listing available plugins while the tool specification owns the installation criteria.

## Testing

- Update tool specification tests to verify the stricter eligibility and serialization guidance.

GitOrigin-RevId: 6ebfdd864a76316ab59a0624dc4d7d3abda39a98
2026-07-14 04:29:57 +00:00
Won Park 0d78fa8846 Restrict Guardian reviewer tools (#32945)
## What changed

- Limit Guardian reviewer sessions with an environment to `exec_command`,
  `write_stdin`, and `view_image`.
- Exclude general tool sources from Guardian reviewer tool planning.

## Testing

- Extend the Guardian request snapshot test to assert the exact model-visible
  tool list.

GitOrigin-RevId: 80ba7011c23c32d163aaad906087fac396cc70fa
2026-07-14 04:15:19 +00:00
richardopenai 80c6cd3014 Allow injecting the models manager into ThreadManager (#32911)
## Why

Embedding callers need to control whether model catalogs are persisted to disk.

## What changed

- Accept a shared models manager when constructing `ThreadManager` instead of always creating a cached manager internally.
- Add provider APIs for creating uncached model managers. OpenAI-compatible providers fetch on each `OnlineIfUncached` refresh without reading or writing `models_cache.json`.
- Keep existing app server, MCP server, sample, and test callers on the standard cached manager.

## Testing

- Verify an uncached manager fetches on every refresh.
- Verify an injected uncached manager controls thread refresh behavior and does not create `models_cache.json`.

GitOrigin-RevId: 8bb646054ecec4ccb865b2bf56249384916ea9db
2026-07-14 01:06:11 +00:00
Ahmed Ibrahim 4657ab06c6 Derive collaboration settings from turn context (#32900)
## Why

`TurnContext` stored model and reasoning settings both as resolved turn fields and inside `CollaborationMode`, requiring the copies to stay synchronized when the model changed.

## What changed

- Store the mode and collaboration-mode developer instructions directly on `TurnContext`.
- Reconstruct `CollaborationMode` from those values plus the turn's current model and reasoning effort when callers need it.
- Read the mode directly for plan-mode checks, lifecycle events, and telemetry.

GitOrigin-RevId: b8fccafdd5d5cbccc84bc70d542588087ddf0093
2026-07-13 23:48:42 +00:00
briansong-oai 2ca20d5224 Expose structured standalone web search results (#32898)
## Why

Standalone web search can return structured result DTOs separately from its
model-facing text output. App-server clients need access to that data without
coupling Codex to every result type or field.

## What changed

- Preserve the optional `results` array from `/v1/alpha/search` as opaque JSON
  through web-search completion events, thread history, and app-server
  `webSearch` items.
- Keep responses from older endpoints compatible when `results` is absent, and
  allow clients to ignore result types and fields they do not understand.
- Regenerate the protocol schemas and TypeScript definitions for the optional
  field.

## Testing

- Cover responses with missing, empty, and forward-compatible result payloads.
- Verify standalone web-search results round-trip through app-server item
  notifications and thread-item conversion.

GitOrigin-RevId: 739ef5694ece5733f7b8749ec41d6bfa3f33c8c5
2026-07-13 23:37:35 +00:00
Dylan Hurd 090f4de37b Route blocked network requests to their owning calls (#32897)
## Why

Policy-blocked proxy requests must terminate the corresponding active tool call and preserve the correct approval result, including when multiple calls are running concurrently.

## What changed

- Resolve a blocked request's execution ID to its registered active network call before recording the policy denial.
- Preserve an outcome already recorded for that call, and cancel the owning call after storing a new denial.

## Testing

Expand network approval integration coverage for Guardian and user decisions, permission hooks, persisted policy amendments, concurrent calls, timeouts, cancellations, and unattributed proxy requests.

GitOrigin-RevId: 961901bbc07cc498309453ec78cda1a56ab00a4b
2026-07-13 23:33:58 +00:00
Matthew Zeng 7fdf2f254b Serialize plugin install requests (#32894)
## What changed

- Mark `request_plugin_install` as not supporting parallel tool calls so install requests execute serially.
- Add a unit test covering the handler's parallel-call capability.

GitOrigin-RevId: 5f2c8184562bd776b0e527e5e258c61c604a0910
2026-07-13 23:17:38 +00:00
jif bb947e8e36 Tag shell tool telemetry by command category (#32887)
## What changed

Add a `command_category` tag to tool result telemetry for `exec_command` and
`shell_command` invocations. Classify parsed commands as `read`, `list_files`,
`search`, or `unknown`; use `mixed` when a script contains multiple categories.

GitOrigin-RevId: 1edacb38c7be9b03af4f2fc86746184f19067592
2026-07-13 22:34:16 +00:00
XMLIU-oai 19a000259d Forward turn metadata in standalone web search (#32835)
## What changed

- Add optional serialized Codex turn metadata to extension tool calls.
- Populate it from the current turn context and send it as the
  `x-codex-turn-metadata` header on standalone web search requests.

## Testing

- Extend the app-server web search integration test to verify that client
  metadata, including the model ID, reaches the standalone search request.

GitOrigin-RevId: c0950108d89a1d317ac94ccd23efcee72fffc6f0
2026-07-13 16:52:18 +00:00
jif 92938d880e Restrict spawned-agent models to the active backend (#32751)
## Why

Model overrides for `spawn_agent` must be compatible with the multi-agent backend used by the current turn.

## What changed

- Carry each model's multi-agent backend metadata into `ModelPreset`.
- Filter the advertised `spawn_agent` model overrides for multi-agent v2 and reject overrides assigned to another backend.
- Limit error suggestions to picker-visible, backend-compatible models.

## Testing

Added coverage for hiding incompatible models from the tool description and rejecting them during spawn validation.

GitOrigin-RevId: 22c12aba67df46e9743a74f019b72a1b8b76b308
2026-07-13 09:52:27 +00:00
jif ea15456284 Expose model overrides for multi-agent v2 spawns (#32749)
## What changed

- Add the `features.multi_agent_v2.expose_spawn_agent_model_overrides` setting, enabled by default, to expose `model` and `reasoning_effort` on the v2 `spawn_agent` tool.
- Keep these controls available when other spawn metadata is hidden, while allowing them to be disabled independently.
- Add root-agent and subagent guidance that overrides require a partial or context-free fork and should only be used when explicitly authorized.

## Testing

- Cover configuration parsing and defaults, usage-hint preservation, and tool-schema behavior with override exposure enabled and disabled.

GitOrigin-RevId: 92370498108c96fbd51f32965624ce531e991d9a
2026-07-13 09:48:33 +00:00
Dylan Hurd ea0fd84d94 Align Guardian reviews with session configuration (#32747)
## What changed

- Include permission instructions in Guardian review requests and let the review model use its configured tool mode and standard tool plan instead of a Guardian-specific direct-tool override.
- Refine the Guardian policy for tenant policy precedence, authorization scoring, prompt-injection handling, read-only investigation, and post-denial user approval.
- Simplify low-risk allow responses to `{"outcome":"allow"}` regardless of authorization scoring.

## Testing

- Update Guardian request-layout snapshots to cover the permission instructions included in initial and follow-up reviews.

GitOrigin-RevId: eb83571ef61f7b4e854c12e13e7163c6fab43f00
2026-07-13 09:44:56 +00:00
Owen Lin c4318c386d Include terminal errors in turn completion events (#32280)
## What changed

- Add an optional `error` payload to `TurnCompleteEvent` and omit it when a turn completes without an error.
- Preserve the full terminal `ErrorEvent` through the turn lifecycle so the completion event includes the same error details emitted separately by `EventMsg::Error`.

## Testing

- Extend the stream-error integration test to verify that `TurnCompleteEvent` contains the emitted error and that the next turn can still proceed.

GitOrigin-RevId: 8d32942a44132763076130102d8b89ab356d59d0
2026-07-10 22:04:03 +00:00
Owen Lin bca577d69a Include start times in terminal turn events (#32263)
## What changed

- Add an optional `started_at` Unix timestamp to `TurnCompleteEvent` and
  `TurnAbortedEvent`.
- Populate the timestamp from turn timing state when a turn completes or is
  aborted.
- Preserve the timestamp when synthesizing interrupted fork history and when
  importing external sessions.

## Testing

- Verify that interrupting a turn emits a `TurnAbortedEvent` with a start
  timestamp.

GitOrigin-RevId: 75b3911b95c060e5fc1843a5e293d8fe47377186
2026-07-10 20:25:03 +00:00
Dylan Hurd b66c25c6a3 Preserve local path conventions in automatic approvals (#32261)
## Why

Drive-shaped POSIX paths such as `/C:/workspace` can be mistaken for Windows
paths when an automatic approval request converts them from `PathUri`.

## What changed

- Keep approval paths as `PathUri` values together with their environment ID
  until the automatic review request is built.
- Recover host-native paths for local working directories when strict
  conversion cannot determine the path convention.
- Continue rejecting incompatible paths from remote environments.

## Testing

Add coverage for drive-shaped local POSIX paths, foreign remote paths, and
preserving apply-patch path URIs while building approval actions.

GitOrigin-RevId: 3fd31cfb4e8b46f9968ff66d5e986ca777430185
2026-07-10 20:18:51 +00:00
Dylan Hurd 2da1b12822 Let permission hooks resolve strict auto-review requests (#32232)
## What changed

- Run permission-request hooks before routing approvals to the automated reviewer or user, including when `strict_auto_review` is enabled.
- Centralize approval resolution so hook, automated-reviewer, and user decisions share rejection handling and report the correct telemetry source.

## Testing

- Add an integration test showing that an allow hook can approve a shell command during strict auto-review without invoking the automated reviewer.

GitOrigin-RevId: 18e9d76baee6cbae9d35ae517250f2f82270a9d2
2026-07-10 18:12:27 +00:00
pakrym-oai c8dc8e5fd5 Propagate workspace roots to exec-server sandboxes (#32214)
## What changed

- Pass configured workspace roots from core to the exec server so filesystem and process sandbox permissions are materialized against the intended roots.
- Preserve an explicitly empty workspace-root list instead of treating the sandbox working directory as an implicit root.
- Initialize filesystem sandbox contexts with their working directory as the default workspace root.

## Testing

- Add end-to-end coverage for patch and command writes inside and outside workspace roots.
- Verify remote filesystem and process sandboxes do not grant access through an empty workspace-root list.

GitOrigin-RevId: 6684c8f7de50970b45a29e2a6323df954c96f9f6
2026-07-10 16:55:01 +00:00
jif 6138909d6e Keep unified exec output collection bounded (#32150)
## Why

Unified exec can drain process output multiple times while waiting for a command. Collecting those drains into an uncapped buffer allows large commands to exceed the output collection limit.

## What changed

- Accumulate drained output through the capped head/tail buffer so collection remains bounded while preserving the beginning and end of the stream.
- Include a `... N bytes omitted ...` marker when the collection cap drops output.
- Calculate the original token estimate from all observed bytes and preserve omission metadata through truncation and sandbox-denial responses.

## Testing

- Cover repeated drains, previously omitted output, omission markers, and large-output summaries.

GitOrigin-RevId: c6e2efeb875ed8f35914365eab7431f25fd3484c
2026-07-10 12:22:04 +00:00
Channing Conger 8cf9a1b1f8 code-mode: fall back to using in process v8 if we fail to resolve external process (#31899)
## Why

Not every Codex distribution currently includes the
`codex-code-mode-host` companion binary. Enabling the process-host
feature should not make code mode unavailable on those surfaces while
packaging support is being completed.

## What changed

- Fall back to an in-process code-mode session only when spawning the
companion binary returns `io::ErrorKind::NotFound`.
- Keep permission, handshake, timeout, and other host failures visible
instead of silently falling back.
- Store the provider's owned-process/in-process choice as one
enum-backed state so later sessions reuse the fallback decision.
- Preserve the underlying spawn `io::Error` while retaining the host
path in the displayed error.
- Update provider, `CodeModeService`, and end-to-end coverage to verify
successful fallback execution.

## Test plan

- `just test -p codex-code-mode`
- `just test -p codex-core missing_process_host`
2026-07-09 14:40:10 -07:00
thomas 8347b8de21 [codex-apps] Filter optional file fields by tool schema (#31686)
## Summary

Codex Apps file parameters are exposed to the model as local paths,
uploaded at execution time, and rewritten into provided-file payloads
before the MCP tool call.

The rewrite currently includes the documented optional fields
`mime_type` and `file_name` for every file parameter. Apps with strict
schemas can reject those fields when they are not declared.

## Changes

- Derive the supported optional file fields from each
`openai/fileParams` parameter's raw input schema before replacing it
with the model-visible local-path schema.
- Always include `download_url` and `file_id`.
- Include `mime_type` and `file_name` only when that specific file
parameter's schema accepts them, including schemas that allow additional
properties.
- Handle scalar and array file parameters, including items-only arrays,
composed schemas, and local JSON Schema references.
- Preserve the existing restriction that only the host-owned Codex Apps
MCP server can use this upload path.

This supports tools with different file contracts in the same app: one
parameter can accept the optional fields while another remains strict.

## Validation

- `just test -p codex-mcp`
- `just test -p codex-core mcp_openai_file`
- `just test -p codex-core codex_apps_file_params_`
- `just fix -p codex-mcp`
- `just fix -p codex-core`
- `just fmt`
- `git diff --check`
- Manually verified in the Codex Electron app that:
  - a strict file schema receives only `download_url` and `file_id`
  - a rich file schema also receives `mime_type` and `file_name`

Related: #31330
2026-07-09 14:32:23 -07:00
sayan-oai a6b99ee5c4 code-mode: retain shared MCP types for deferred tools (#31745)
## Why

When MCP tools are deferred behind `tool_search`, Code mode keeps them
callable but omits their individual declarations from the initial `exec`
description. The shared MCP `CallToolResult` types were derived only
from directly rendered tools, so deferring every MCP tool also removed
the common response contract that models need to interpret MCP results.

This restores that contract without undoing the context savings from
deferred tool definitions. This is a follow-up to #29486.

## What changed

- Track deferred Code-mode tool definitions separately from directly
rendered definitions.
- Render the shared MCP type preamble when either direct or deferred MCP
tools are available.
- Keep deferred tool declarations out of the initial prompt.
- Add unit and integration coverage for deferred MCP tools.

## Testing

- `just test -p codex-code-mode-protocol`
- `just test -p codex-core
code_mode_only_guides_all_tools_search_and_calls_deferred_app_tools`
2026-07-09 08:17:13 -07:00
Won Park a7c72aee8b Use the image generation extension by default (#31596) 2026-07-09 12:25:19 +09:00
Michael Bolin 5892c7b69d model-provider: route model discovery through HTTP client factory (#31361) 2026-07-09 02:32:10 +00:00
b780738014 Update models.json (#21818)
Automated update of models.json.

---------

Co-authored-by: aibrahim-oai <219906144+aibrahim-oai@users.noreply.github.com>
Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
Co-authored-by: Sayan Sisodiya <sayan@openai.com>
2026-07-08 16:24:12 -07:00
olliem-oai 3eb56537eb Update auto review prompting (#31480)
## Why
Auto-review performance is weaker because of confusing instructions
about sandbox permissions, and because it is given many tools which are
irrelevant to it.

## What
* Update the auto review prompt
* Remove the permissions_instructions developer message
* Only pass exec_tool and view_image tool to the reviewer

## Validation
`just fmt`
`cargo test -p codex-core --lib --quiet`
2026-07-08 23:15:43 +00:00
Channing Conger c55cb4b363 code-mode: make all approvals trigger elicitation pause (#31650)
### summary

We want to pause code-mode from yielding back to the model when a
subcommand triggers an approval prompt. This means that all of these
previously inline blocking requests should also take out a
ElicitationService registration.

This also does some plumbing refactoring to request patch approval to
make it match the other `request_*_approval` methods in that it blocks
on the approval in the function instead of returning the oneshot
channel, this affords our ability to encapsulate the ElicitationService
registration via RAII.

Adds tests to confirm the blocking behavior for code_mode both in suite
tests and that the session holds them.
2026-07-08 15:27:04 -07:00
Owen Lin 602dbb42dc core: stop emitting legacy command events directly (#31629)
## Description

This PR removes the last path in core that emits `ExecCommandBegin` /
`ExecCommandEnd` directly.

Every command execution now starts and completes through canonical
`ItemStarted` / `ItemCompleted(TurnItem::CommandExecution)`. The
existing `HasLegacyEvent` compatibility layer still fans out Begin/End
afterward, so raw core event consumers and legacy rollout replay keep
seeing the same events.

`UnifiedExecInteraction` is dormant today. Live unified exec uses
`UnifiedExecStartup` for command lifecycle and `TerminalInteraction` for
`write_stdin` and polling, so this is code cleanup rather than a current
product behavior change. The main win is the code-level invariant where
all core flows emit `TurnItem` instead of legacy events.

## What changed

- Removed the `UnifiedExecInteraction` branches that emitted legacy
command events directly.
- Routed every command source through the existing canonical
`CommandExecution` lifecycle and compatibility fanout.
2026-07-08 20:53:36 +00:00
Owen Lin a219b6fdb4 core: migrate standalone web search to extension-owned turn items (#31525)
## Description

This PR migrates standalone web search onto the extension-owned
turn-item path introduced in #31283.

Standalone web search now emits `ExtensionItem::WebSearch` through
generic `TurnItem::Extension`, while app-server still exposes the
existing typed `ThreadItem::WebSearch` JSON shape. Hosted Responses API
web search stays on core-owned `TurnItem::WebSearch`.

## What changed

- Added `web_search::WebSearchItem` and `WebSearchAction` to
`codex-extension-items` under the stable `web.search` kind.
- Collapsed `ExtensionTurnItem` to generic `{ item, legacy_events }` now
that no typed extension special cases remain.
- Kept the existing `WebSearchBegin` / `WebSearchEnd` compatibility
events and canonical-first ordering.
- Updated app-server projection/history and generated TypeScript; the
app-server JSON schema is unchanged.
2026-07-08 09:40:00 -07:00
Owen Lin f1affbac5e core: support extension-owned turn items (#31283)
## Description

This PR adds a `codex-extension-items` crate for extension-owned
`TurnItem` schemas, and updates standalone image generation to start
using it via `TurnItem::Extension`.

This gives us a way to prevent Core from having to be aware of all
extension items. App-server still exposes the existing public
`ThreadItem::ImageGeneration` shape, now by wrapping the same shared
`image_generation::ImageGenerationItem` type.

The new `codex-extension-items` crate is necessary because the image gen
extension item is used by:
- `codex-image-generation-extension`, which produces it.
- `codex-tools / core`, which carry it generically.
- `codex-protocol`, which serializes it into lifecycle events and
rollouts.
- `app-server protocol`, which wraps it in public
`ThreadItem::ImageGeneration`

```
extension implementation
        ↓
codex-extension-items
        ↓
protocol / tools / app-server
```

We keep the hosted Responses API image generation as
`TurnItem::ImageGeneration` because core still owns its persistence and
legacy fanout.

### Before

Standalone image generation is implemented as an extension, but its item
representation previously lived in the core protocol. This sets the
precedent that core is aware of all extension items, which would be good
to avoid.

```
image-gen extension
→ constructs codex_protocol::ImageGenerationItem
→ emits ExtensionTurnItem::ImageGeneration
→ core matches ImageGeneration specially
→ protocol stores TurnItem::ImageGeneration
```

### After
```
image-gen extension
→ constructs extension-owned ImageGenerationItem
→ emits generic ExtensionItem
→ core transports/persists it generically
→ app-server wraps ImageGenerationItem as ThreadItem::ImageGeneration
```

Future extension items can have typed app-server APIs without adding a
new `TurnItem` variant, `ExtensionTurnItem` variant, or core emitter
match arm.

## What changed

- Added `codex-extension-items` with the closed `ExtensionItem` enum and
shared `image_generation::ImageGenerationItem` schema.
- Added generic `TurnItem::Extension(ExtensionItem)` and
`ExtensionTurnItem::Extension { item, legacy_events }` paths.
- Updated standalone image generation to emit a typed extension item and
provide its existing legacy `ImageGenerationBegin` /
`ImageGenerationEnd` events explicitly.
- Kept canonical lifecycle ordering: core emits `ItemStarted` /
`ItemCompleted` before extension-provided legacy events.

## Follow-up

Standalone web search still uses its typed special-case path. Migrating
it later would let `ExtensionTurnItem` collapse into a single
extension-item struct.
2026-07-08 03:55:13 +00:00
Winston Howes 07d631875e Use canonical indexed web access field (#31289)
## Summary

- Rename the hosted web-search wire field to the canonical
`indexed_web_access` spelling.
- Preserve existing indexed-search behavior.

## Rollout

Merge and release only after server support for `indexed_web_access` is
fully deployed.

## Testing

- `just fmt`
- `just test -p codex-tools
web_search_tool_spec_serializes_expected_wire_shape`
- Blocking CI passed, including indexed web-search integration coverage.
2026-07-07 16:17:12 -07:00
Owen Lin 6b4882528e feat(core): emit canonical collab wait items (#31301)
This PR depends on [#31296](https://github.com/openai/codex/pull/31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes the v1 and v2 wait paths emit canonical
`TurnItem::CollabAgentToolCall` lifecycle instead of
`CollabWaitingBegin` / `CollabWaitingEnd` directly.

Both paths already used the same legacy waiting events before this PR.
The v1 item carries receiver metadata and final agent statuses for its
target agents; v2 waits for mailbox activity rather than specific
agents, so it keeps those fields empty, matching the existing v2 legacy
payload.

App-server v2 consumes the canonical item directly and ignores the
mapped legacy wait events.

## Why

Wait is separate from the other collab tools because it is multi-target
and has distinct timeout/status behavior. Keeping it last also lets this
PR remove the old helper that only existed to shape legacy wait status
entries in core.

## What changed

- Emit canonical collab wait items from both v1 and v2 wait handlers.
- Preserve receiver metadata and agent status snapshots on completed
wait items.
- Remove the old core helper for building legacy wait status entries.

## Follow-up

The next stack PR, [#30188](https://github.com/openai/codex/pull/30188),
writes canonical `TurnItem` values to paginated rollout files.
2026-07-07 20:59:02 +00:00
Owen Lin 058d97c5dc feat(core): emit canonical collab tool call items (#31300)
This PR depends on [#31296](https://github.com/openai/codex/pull/31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes the non-wait v1 collaboration tools—spawn, send input,
resume, and close—emit canonical `TurnItem::CollabAgentToolCall`
lifecycle instead of their legacy begin/end events directly.

App-server v2 consumes the canonical collab items directly, ignores the
mapped legacy events, and applies close-agent thread-watch cleanup from
the completed item.

## Why

These four tools share the same single-target lifecycle shape. Wait
stays separate because it carries multi-target status snapshots and has
its own status-shaping cleanup.

## What changed

- Add shared helpers for emitting canonical collab tool-call lifecycle.
- Migrate spawn, send input, resume, and close handlers.
- Move close-agent watcher cleanup onto canonical completed collab
items.
2026-07-07 13:35:57 -07:00
Owen Lin 1bd9d841ca feat(core): emit canonical sub-agent activity items (#31299)
This PR depends on [#31296](https://github.com/openai/codex/pull/31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes the MultiAgentV2 spawn, message/follow-up, and interrupt
paths emit completed canonical `TurnItem::SubAgentActivity` items
instead of `SubAgentActivityEvent` directly.

App-server v2 now applies interrupted-agent thread-watch cleanup from
the canonical completed item and ignores the mapped legacy activity
event.

## Why

Sub-agent activity is separate from the v1 collab tool begin/end
lifecycle. Keeping it separate makes the v2 watcher side effect
reviewable without mixing in the larger collab tool-call migration.

## What changed

- Emit canonical sub-agent activity items from v2 spawn,
message/follow-up, and interrupt paths.
- Move missing-thread watcher cleanup onto canonical completed activity
items.
- Update focused app-server coverage to exercise canonical interrupted
activity.
2026-07-07 12:57:42 -07:00
Owen Lin f659eb12bc feat(core): emit canonical dynamic tool call items (#31298)
This PR depends on [#31296](https://github.com/openai/codex/pull/31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes dynamic tools emit canonical `TurnItem::DynamicToolCall`
lifecycle instead of `DynamicToolCallRequest` /
`DynamicToolCallResponse` directly.

App-server v2 now sends the client `DynamicToolCall` request from the
canonical item start. It ignores the mapped legacy request/response
events, so clients receive one item start and one tool request.

## Why

Dynamic tools are a separate migration boundary because their start
event also drives a client request. Keeping that routing change isolated
makes it easier to verify that the request still happens exactly once.

## What changed

- Emit in-progress and completed/failed dynamic tool items from the
dynamic tool handler.
- Move app-server client request dispatch onto canonical dynamic item
starts.
- Add focused app-server coverage for the canonical start notification
and client request.
2026-07-07 08:32:14 -07:00
Owen Lin cca16a1087 feat(core): emit canonical command execution items (#31297)
This PR depends on [#31296](https://github.com/openai/codex/pull/31296)
for the canonical-to-legacy event mappings.

## Description

This PR makes command execution emit canonical
`TurnItem::CommandExecution` lifecycle from both the shell tool path and
user `/shell` commands.

App-server v2 consumes the canonical command items directly and ignores
the mapped `ExecCommandBegin` / `ExecCommandEnd` compatibility events,
so clients still receive one command item lifecycle.

`UnifiedExecInteraction` stays on the legacy path because
`TerminalInteraction` is still the v2 surface for stdin and poll events.
Emitting a command item there would render the same wait twice.

## Why

This is the first live producer migration after the compatibility
mappings in #31296. Keeping command execution separate makes the unified
exec exception reviewable without mixing in dynamic tools or multi-agent
behavior.

## What changed

- Emit canonical command execution items from shell tool events and user
shell commands.
- Preserve the existing unified exec interaction carveout.
- Move app-server command deduplication and completion bookkeeping onto
canonical item events.
- Update unified exec coverage to assert the completed command item.
2026-07-06 21:22:51 -07:00
1013295c2d fix: attribut network requests to the exact exec on linux (#29697)
## Why

Managed-network commands within one Codex conversation share the same
HTTP and SOCKS proxy ingress. When several exec calls run concurrently,
the proxy sees the requested destination but cannot tell which exec
opened the connection.

For example:

```text
exec A: curl https://example.com/a ─┐
                                    ├─> conversation proxy ─> Guardian
exec B: curl https://example.com/b ─┘                        host: example.com
                                                               trigger: unknown
```. Three parallel network execs reached Guardian without their
triggering call IDs or commands. Guardian denied the requests, but Codex
could not safely associate those outcomes with the individual tool
calls.

## What changes

Keep the shared proxy ingress and tag each connection at the existing
trusted Linux bridge:

```text
exec A ─> existing Linux bridge ─> [token A][proxy bytes] ─┐
                                                           ├─> shared HTTP/SOCKS ingress
exec B ─> existing Linux bridge ─> [token B][proxy bytes] ─┘
                                                                    │
                                              token A ─> exec A ─────┤
                                              token B ─> exec B ─────┘
```

The complete path is:

```text
active exec registration
        │
        ├─ registers its UUID as a short-lived attribution token
        ├─ passes the token to the Linux sandbox helper
        ├─ helper removes the token before launching the user command
        ├─ existing host bridge prepends the token to each proxy connection
        ├─ shared proxy consumes the bounded attribution frame
        └─ proxy attaches the matching execution-scoped state
                ├─ Guardian receives the exact call ID and command
                └─ a denial finishes/cancels the matching tool call
```

Dropping the active or deferred exec registration removes the token.
Connections that were already accepted retain their resolved
attribution; new connections using an expired token fail closed.

## Before and after

Before, Guardian could receive only the network destination:

```json
{
  "tool": "network_access",
  "host": "www.17track.net",
  "port": 443,
  "protocol": "https"
}
```

After, the same request includes the action that caused it:

```json
{
  "tool": "network_access",
  "host": "www.17track.net",
  "port": 443,
  "protocol": "https",
  "trigger": {
    "callId": "exec-network-first",
    "command": ["/bin/sh", "-c", "curl https://www.17track.net"]
  }
}
```

## Listener accounting

This PR does **not** create proxy listeners per exec.

```text
Existing topology:
  one conversation -> one HTTP listener + optional one SOCKS listener

Discarded per-exec approach:
  one conversation -> existing listener pair
                   + up to one additional listener pair per active exec

This PR:
  one conversation -> existing listener pair only
                   + one small token-map entry per active exec
```

The Linux sandbox already creates a trusted routing bridge for each
sandboxed command. This PR adds a short frame write to that bridge
rather than introducing another listener, task, or proxy process.

The existing conversation-scoped listener pair remains. Making a single
proxy service shared across multiple conversations would be a separate
multi-tenant architecture change involving per-conversation policy,
configuration, audit, and Guardian routing.

## Keeping the implementation small

The attribution is bound once, when the TCP connection enters the proxy.
The ingress installs an execution-scoped clone of the existing
`NetworkProxyState`, so the established HTTP, SOCKS, MITM, policy,
audit, and blocked-request paths continue using their existing state
lookup.

This avoids plumbing a new request-context type through every protocol
handler. Outside the two ingress wrappers, protocol-specific request
handling is unchanged.

## Security behavior

- Tokens are generated from the existing random execution registration
IDs.
- The trusted Linux helper consumes and removes the token before
executing user code.
- Attribution frames have a fixed magic prefix, bounded token length,
and bounded read timeout.
- Unknown or expired tokens close the connection.
- A token presented to a proxy for another environment closes the
connection.
- Existing unframed callers preserve the current conservative
attribution behavior.

## Platform scope

Exact bridge attribution is enabled on Linux. macOS and Windows retain
their current shared-proxy behavior.

## Test coverage

The concurrent end-to-end test starts two managed-network execs together
and synchronizes them so both are active before either connects. It then
inspects the two Guardian requests and compares the complete attribution
pairs:

```text
(exec-network-first,  exact first command)
(exec-network-second, exact second command)
```

Focused proxy coverage verifies the bounded frame and that a registered
framed connection receives the matching execution and environment state.

## Scope

This fixes the Linux network-to-exec attribution path and records a
denial against the exact matching tool call. It intentionally does not
change:

- delivery of an entirely unattributed denial to the parent turn;
- how parallel denials count toward the Guardian circuit breaker;
- how the UI displays the rejection reason or completed-turn state.

Those remain separate concerns from attribution.

## Relationship to #29456 and #29668

#29456 made the proxy environment and sandbox policy come from the same
prepared network context. This PR adds the execution token to that
prepared launch and consumes it at the shared ingress.

This follows #29668's shared-ingress framing direction, but completes
the production registration, Linux bridge, core call mapping, denial
mapping, and concurrent end-to-end path. It also keeps attribution in
the existing per-connection proxy state instead of introducing
request-context plumbing through every HTTP, SOCKS, and MITM handler.
This PR is intended to supersede #29668 for the Linux attribution fix.

---------

Co-authored-by: viyatb-oai <viyatb@openai.com>
Co-authored-by: Codex <noreply@openai.com>
2026-07-06 14:51:34 -07:00
Dylan Hurd aa94ea1397 chore(approvals) consolidate guardian calls for shell tools (#31267)
## Summary
As part of our effort to start simplifying approvals code, this PR
extracts Guardian approvals logic from shell tool calls, and replaces it
with the ApprovalAction abstraction instead. This way, tools don't need
to know about Guardian at all.

## Testing
- [x] Adds integration test
2026-07-06 13:23:01 -07:00
Channing Conger 84fe70c30e elicitations: Move to shared ElicitationService (#30627)
## Why

Code-mode tool results could return to the model while an MCP
elicitation was still waiting for user input. This differed from
parallel tool calling and could let the model continue before the user
resolved the request.

We need one session-level view of outstanding elicitations so tool
runtimes can consistently hold results until every pending elicitation
is resolved.

  ## What changed

- Added a counted, session-owned ElicitationService with RAII
registrations.
- Registered both core-originated and server-originated MCP elicitations
with the service.
- Migrated out-of-band elicitation tracking and unified exec timeout
pausing to the shared service.
- Made code-mode functions.exec and functions.wait capture their runtime
result normally, then hold it before returning while an elicitation is
outstanding.
  - Kept terminate: true immediate; only its result is held.
  - Preserved model-visible wall time across the elicitation hold.
- Kept the behavior session-scoped, with concurrent elicitations holding
the pause until all registrations are released.
2026-07-06 11:20:32 -07:00
Michael Bolin beca198b8a telemetry: log structured direct tool-call timing (#30334)
## Why

App-server deployments can consume structured JSON logs for operational
measurements without requiring an OTEL exporter. Existing tool-result
telemetry reports the handler outcome, but it does not separate time
spent waiting to dispatch from time spent executing the handler.

A compact completion event for the outer, direct tool call lets
consumers measure those phases and correlate them with a conversation
and turn. Code-mode calls are intentionally excluded so nested runtime
calls do not create overlapping events that are easy to double-count.

## What changed

- Added a
[`ToolCallTimingGuard`](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/core/src/tools/parallel.rs#L32)
around direct tool calls. Event-only strings and timing state are
captured only when the `codex_core::tools::parallel` `INFO` target is
enabled.
- Added a
[`codex.tool_call`](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/core/src/tools/parallel.rs#L313)
completion event with conversation, turn, tool, call, trace, dispatch,
handler, and total timing fields.
- Recorded the execution-start marker after the dispatch lock is
acquired. Event emission snapshots that marker once so a concurrently
starting dispatch cannot produce internally inconsistent fields.
- Limited the event to `ToolCallSource::Direct`; [unit
coverage](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/core/src/tools/parallel.rs#L365)
verifies code-mode calls are ignored.
- Added [cancellation
coverage](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/core/src/tools/parallel.rs#L408)
that holds the execution gate and verifies a call cancelled before
admission emits exactly one dispatch-only timing event.
- Added reusable
[`JsonLogCapture`](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/app-server/tests/common/json_logging.rs#L15)
support, a [JSON-logging-specific `TestAppServer`
constructor](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/app-server/tests/common/test_app_server.rs#L172),
and an [end-to-end app-server
test](https://github.com/openai/codex/blob/141110a73cff041c42fd51f47e363e83df1dde51/codex-rs/app-server/tests/suite/logging.rs#L52)
that drives a direct `exec_command` through the public v2 JSON-RPC API
and validates the emitted JSON event.

Exec-server-specific request and process timing remains in the stacked
PR #30901.

## Suggested logging filter

```bash
LOG_FORMAT=json \
RUST_LOG='warn,codex_core::tools::parallel=info' \
codex app-server
```

## Event example

Identifier and timing values are illustrative.

### `codex.tool_call`

```json
{
  "timestamp": "2026-06-27T03:45:20.443Z",
  "level": "INFO",
  "fields": {
    "message": "tool call completed",
    "event.name": "codex.tool_call",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "conversation.id": "67e55044-10b1-426f-9247-bb680e5fe0c8",
    "turn_id": "019f04f8-6ac2-78f1-8625-f04a6d35af18",
    "tool_name": "exec_command",
    "call_id": "call_7b8483",
    "tool_source": "direct",
    "execution_started": true,
    "dispatch_duration_ms": 12,
    "handler_duration_ms": 431,
    "total_duration_ms": 443
  },
  "target": "codex_core::tools::parallel"
}
```

If execution never starts, `execution_started` is `false`,
`handler_duration_ms` is `0`, and `dispatch_duration_ms` covers the full
observed lifetime.

If a duration cannot be represented as an unsigned 64-bit millisecond
value, all three duration fields are omitted rather than populated with
a sentinel that could corrupt downstream calculations.

## Test plan

- `just test -p codex-core
tool_call_timing_guard_ignores_code_mode_source`
- `just test -p codex-core
cancellation_before_dispatch_admission_logs_dispatch_only_timing`
- `just test -p codex-app-server
app_server_emits_structured_tool_call_timing_event`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/30334).
* __->__ #30334
2026-07-02 13:53:56 -07:00