Commit Graph
102 Commits
Author SHA1 Message Date
iceweasel-oai 101d6b8cb2 Preserve foreign paths in background terminal listings (#35850)
## Why

Background terminal working directories can use a path convention from a
different platform than the app-server host. Converting them to host-native
absolute paths can reject otherwise valid terminal entries and fail the list
request.

## What changed

- Represent `ThreadBackgroundTerminal.cwd` with `LegacyAppPathString` at the
  protocol boundary.
- Convert terminal `PathUri` values directly to their inferred native path
  strings instead of validating them against the host platform.

## Testing

Add protocol round-trip coverage for POSIX, Windows drive, and Windows UNC
working directories.

GitOrigin-RevId: d766d54bdc191e75955fb419bec6e60c65f52298
2026-07-29 00:09:15 +00:00
Eric Ning 12b961d4c5 Expose plugin eligibility metadata in app-server summaries (#35837)
## What changed

- Add nullable `disabledReason` and `eligiblePlanTypes` fields to v2
  `PluginSummary` responses and generated schemas.
- Preserve the remote catalog values across discovered, installed, and cached
  plugin summary paths while returning `null` for local plugins and older
  remote responses.
- Treat unrecognized disabled reasons as `unknown` for forward compatibility.

## Testing

- Cover protocol round trips, remote summary propagation, unknown disabled
  reasons, and app-server responses for admin-disabled and plan-ineligible
  plugins.

GitOrigin-RevId: 657a7ea6f838a6ff8bd1769ebcca0f3432684437
2026-07-28 22:28:08 +00:00
joeytrasatti-openai 85c6da1c79 Add persisted sections for organizing threads (#35722)
## What changed

- Replace the `isPinned` thread metadata and filters with an optional persisted
  `section` and `sectionId`.
- Add the paginated `threadSection/list` app-server method so clients can
  discover sections even when they contain no threads.
- Seed a stable `Pinned` section, validate section assignments, and support
  filtering for a specific section or for unsectioned threads.

## Testing

- Cover section protocol serialization, listing and pagination, metadata
  updates, filtering, persistence, migration compatibility, and operation
  without SQLite state.

GitOrigin-RevId: 7972b5471d29317b9387bfd90aa9f573f691ad4c
2026-07-28 05:26:16 +00:00
thomas 61de0d8fe8 Upgrade rmcp to 3.0.0-beta.3 (#35720)
## What changed

- Update the `rmcp` model and transport integrations for `3.0.0-beta.3`.
- Preserve legacy `elicitation/create` form requests, schema defaults, metadata, and wire-format compatibility while adopting the new elicitation types.
- Harden OAuth discovery by using GET-first discovery without starting an MCP session, preventing cross-origin header redirects, validating authorization-server and callback issuers, and retaining compatibility with metadata that omits an issuer.
- Keep stored OAuth credentials readable and avoid requiring reauthorization after transient refresh failures.

## Testing

- Add coverage for legacy elicitation round trips, OAuth discovery variants, callback issuer validation, credential migration, and refresh failures.

GitOrigin-RevId: 756197d26f3fd347c28c400228f6b3d06ed493b7
2026-07-28 05:17:25 +00:00
thomas 32329b289d Expose workspace plugin publish capability (#35254)
## What changed

- Add nullable `canPublishToWorkspace` metadata to plugin share contexts and `plugin/share/save` responses.
- Preserve the remote capability through catalog parsing and app-server responses so clients can decide whether to offer workspace-directory publishing.
- Document that clients should fail closed when the capability is unavailable.

## Testing

- Cover remote catalog parsing, share-save response propagation, and protocol serialization.

GitOrigin-RevId: b0346b3b330169838f800dfdf21dfa5db1a47f4d
2026-07-24 22:14:12 +00:00
rafael-oai 41775559ca Expose Browser Use requirements through the app server (#35033)
## What changed

- Parse the `browser_use.disable_auto_review` setting from layered
  `requirements.toml` configuration.
- Return the setting as `browserUse.disableAutoReview` from
  `configRequirements/read` and publish it in the generated JSON and TypeScript
  schemas.

## Testing

- Add an app-server RPC test covering the Browser Use requirement.

GitOrigin-RevId: 5749d5bc17bcc5b582bf7ed59b8e5b72d6c8f7fc
2026-07-23 23:21:33 +00:00
Kyle Brown 84fa68b429 Attribute command executions to trusted plugin scripts (#35020)
## What changed

- Resolve shell and unified-exec commands against the trusted plugin roots loaded for each turn.
- Add optional `pluginId` and safe plugin-relative `scriptPath` fields to command execution items and legacy execution events, and propagate them through app-server notifications.
- Include the attribution in command execution analytics while rejecting absolute, unsafe, and unattributed script paths.

## Testing

- Cover attribution for cached curated and remote plugin scripts from command execution through core and app-server events.
- Verify analytics serialization and unsafe-path filtering.

GitOrigin-RevId: 02fac3a233284ccfc6642fa502a95f1881dba83d
2026-07-23 22:31:53 +00:00
joeytrasatti-openai 400ee190c3 Add persisted thread pinning to the app server (#34840)
## What changed

- Add `isPinned` to thread responses and allow `thread/metadata/update` to pin or unpin stored threads.
- Add an `isPinned` filter to `thread/list`, including cursor-based pagination and combinations with relationship filters.
- Persist pin state in SQLite without modifying rollout files, default existing threads to unpinned, and preserve pins through reconciliation and archive transitions.

## Testing

- Cover protocol serialization, database migration and indexing, pin updates, filtered pagination, rollout reconciliation, and archive/unarchive behavior.

GitOrigin-RevId: c2eacabd6dae465e2ae6ce8a169e00740960cdb7
2026-07-22 22:54:28 +00:00
jiayuhuang-openai 4ebd976312 Support configurable realtime BEM channel prefixes (#34816)
## What changed

- Route realtime V3 `bemTags` handoffs using `[ANALYSIS]`, `[COMMENTARY]`, and `[FINAL]` prefixes by default.
- Add `codexResponseHandoffChannelPrefixes` to realtime start requests so clients can replace the accepted prefixes for individual channels. Each channel may accept multiple prefixes, and omitted channels retain their defaults.
- Apply the configured prefixes to both complete and streamed handoff messages, without treating empty prefixes as matches.

## Testing

- Cover request deserialization, default and custom routing, partial streamed prefixes, empty-prefix handling, and end-to-end V3 handoffs.

GitOrigin-RevId: d0aef50aa71362a5beef2c6f6d28b8633da4e529
2026-07-22 19:43:35 +00:00
iceweasel-oai 87f71e35b8 Skip missing paths in filesystem sandbox entries (#34598)
## Why

Default read-only protections for project metadata should apply when paths such
as `.git`, `.agents`, and `.codex` exist, without causing sandbox setup to
materialize missing paths as ACL targets.

## What changed

- Add an optional `missing_path_behavior` to filesystem sandbox entries and
  mark default project-metadata protections with `skip`.
- Preserve the behavior through permission transforms and exec/MCP protocol
  serialization while keeping existing path wire variants stable.
- Ignore skip-missing entries when projecting configuration or Windows sandbox
  overrides, while retaining explicit metadata carveouts.

## Testing

- Cover protocol round trips for path and special-path entries.
- Verify default metadata protections and Windows explicit carveout handling.

GitOrigin-RevId: 6df13dadacdd131c44aab9f15a967c81051355c1
2026-07-21 19:17:18 +00:00
Abhinav ee71c4a90f Enforce exact values from managed config requirements (#34597)
## What changed

- Apply managed values for `sqlite_home`, `log_dir`, `model_catalog_json`,
  `check_for_update_on_startup`, `allow_login_shell`, the report-submission
  opt-in, and `windows.sandbox_private_desktop` to the runtime configuration,
  with source-aware warnings when they override configured values.
- Expose these values through `configRequirements/read`, return them from
  `config/read`, include them in session config locks, and show their sources in
  the TUI config debug view.
- Reject app-server writes that overlap an exact managed requirement with
  `configRequirementReadonly` while leaving unrelated sibling keys writable.

## Testing

- Cover runtime overrides, requirement API mapping, config reads and writes,
  session lock serialization, cross-platform path URIs, and debug output.

GitOrigin-RevId: d4e23b6fd7775c1a6dfe2eab313cdcee50b07081
2026-07-21 19:08:58 +00:00
brisebois-oai 6ac68be6fe Accept forceRefetch in plugin list requests (#34573)
## What changed

- Add the optional `forceRefetch` boolean to `PluginListParams` and generated schemas.
- Accept both omitted and enabled values without changing `plugin/list` behavior yet.
- Cover deserialization of the enabled value in the protocol tests.

GitOrigin-RevId: fd4145161e9779638bc0bf18118d5ab5b8478745
2026-07-21 16:30:17 +00:00
charlesgong-openai a30aee8d90 Attribute external agent imports by provider (#34451)
## What changed

- Add an optional opaque `providerId` to `externalAgentConfig/import` for analytics attribution, independently of the `migrationSource` selector.
- Include the provider ID in completed-import and import-failure analytics events.
- Have TUI imports identify their selected migration source as the provider.

## Testing

- Cover provider attribution in app-server import completion and failure tests and analytics serialization tests.

GitOrigin-RevId: 0ee7313a43652e5305939c526bf6b903a79334ad
2026-07-21 02:59:22 +00:00
nhamidi-oai 643de86a19 Add audio output support to dynamic tools and code mode (#34080)
## What changed

- Add `inputAudio` content items to dynamic tool responses, app-server events, thread history, and generated protocol schemas.
- Add an `audio()` code-mode helper that accepts inline data URLs, audio URL objects, and MCP audio blocks.
- Convert MCP audio blocks into model input when audio is supported, and replace unsupported audio with an explanatory text item.
- Reject non-data audio URLs and track audio item counts in dynamic tool analytics.

## Testing

- Cover audio serialization, protocol round trips, thread-history conversion, MCP modality filtering, code-mode helper inputs, and invalid URL handling.

GitOrigin-RevId: 1ed52a8f9c62d4840fb71c5ec736b4a3566243d6
2026-07-18 23:22:13 +00:00
jiayuhuang-openai 312caf176a Seed realtime V3 sessions with initial text items (#34067)
## What changed

- Add an optional `initialItems` field to `thread/realtime/start` for seeding
  realtime V3 session history with `user`, `developer`, and `assistant` text.
- Encode the items in Frameless Bidi session bootstrap payloads for websocket
  and WebRTC transports while preserving existing payloads when the list is
  omitted or empty.
- Reject non-empty initial items for V1 and V2, more than 128 items, any item
  over 8,192 estimated tokens, or a combined total over 8,192 estimated tokens.

## Testing

- Cover protocol serialization, app-server forwarding, websocket and WebRTC
  payloads, empty-list compatibility, version checks, and size limits.

GitOrigin-RevId: 09af367f9a07543e3f8d59b7fa5387f932dc5a6a
2026-07-18 20:59:57 +00:00
nhamidi-oai 97dbd01a3d Add audio variants to user input protocols (#33923)
## What changed

- Add remote and local audio variants to core and app-server user inputs, including generated JSON and TypeScript schemas.
- Preserve audio fields when converting app-server inputs and response content into thread items.
- Keep unsupported audio out of model requests, TUI rendering, text extraction, and truncated tool output, using explicit text placeholders where audio is submitted as a model input.

## Testing

- Cover app-server media conversion, unsupported-input placeholders, TUI omission, and tool-output truncation.

GitOrigin-RevId: 16152bf3af674575ce569764a8b472e032e7569d
2026-07-17 23:14:37 +00:00
brisebois-oai bc5c9161b4 Expose plugin installation interstitial requirements (#33896)
## What changed

- Add nullable `mustShowInstallationInterstitial` metadata to app-server
  `PluginSummary` responses.
- Preserve the remote service value through catalog, installed-plugin cache,
  list, read, and share-list paths.
- Return `null` for local plugins and remote responses that omit the field so
  clients can fail closed when the policy is unavailable.

## Testing

- Cover `true`, `false`, and missing values across remote summary paths and
  app-server plugin endpoints.

GitOrigin-RevId: db79702ee2bfa800a9910d64d933bcabecb3ce70
2026-07-17 20:02:51 +00:00
Felipe Coury 3f0669dbd6 Make parent-owned sub-agent threads read-only in the TUI (#33841)
## Why

Multi-agent V2 spawned threads are controlled by their parent and reject direct
app-server input. The TUI should expose that ownership instead of presenting an
input flow that the server will reject.

## What changed

- Add the experimental `Thread.canAcceptDirectInput` capability for loaded
  threads and populate it from the same policy used to validate `turn/start`
  and `turn/steer`. Stored, unloaded threads report `null`.
- Carry the capability through TUI thread discovery, selection, startup, and
  resume flows, with a compatibility fallback for older app servers.
- Present parent-owned threads as view-only, preserve drafts and queued input,
  block agent-directed commands and settings shortcuts, and keep local
  navigation and inspection commands available.

## Testing

- Cover V1 writable and V2 view-only spawned threads through selection and
  resume.
- Cover composer submission paths, queued and initial input preservation,
  allowed navigation commands, settings shortcuts, and the view-only UI.

GitOrigin-RevId: 495ad051249e5577fb0b0c1cc8c40a0998d04918
2026-07-17 15:14:47 +00:00
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
charlesgong-openai 1c4af96394 Add Cursor support to setup import (#33426)
## What changed

- Detect and import supported Cursor settings, sandbox permissions, MCP servers,
  project instructions, hooks, agents, commands, plugins, and recent chat
  sessions.
- Update the `/import` flow to check Claude Code and Cursor, prompting for a
  source when both have importable data.
- Add `migrationSource` to the app-server detect and import requests so each
  operation uses the selected adapter, while retaining `source` for import
  attribution and backwards compatibility.

## Testing

- Add coverage for Cursor config conversion, hooks, plugins, session discovery
  and conversion, app-server imports, and TUI source selection.

GitOrigin-RevId: a65a1511b6c1c2f9e3e0cfe4f816bb435807282e
2026-07-15 21:03:49 +00:00
Owen Lin da61f7d8e1 Enable paginated thread history in app-server (#33364)
## What changed

- Allow `thread/start` to select experimental `historyMode: "paginated"` when the thread store supports turn and item pagination.
- Resume paginated threads with bounded model context and require `excludeTurns: true` instead of loading full history.
- Return `turnsBackwardsCursor` and `itemsBackwardsCursor` from `thread/resume` so clients can hydrate durable history through `thread/turns/list` and `thread/items/list` while newer records arrive through live notifications.
- Reject operations that still require full history, including `initialTurnsPage`, `thread/read` with `includeTurns: true`, `thread/rollback`, and detached review.
- Make item cursors independent of the optional `turnId` filter.

## Testing

- Cover paginated thread start, cold and live resume, backwards cursor hydration, metadata reads, unsupported operations, and stores without pagination support.

GitOrigin-RevId: c42f9b268e29d049843330f474fa3ecde12f5b8a
2026-07-15 15:29:13 +00:00
Owen Lin e0a3641e6c Support paginated thread history in app-server list APIs (#33152)
## Why

Clients could discover threads with paginated history, but could not page their
turns through `thread/turns/list`.

## What changed

- Route `thread/turns/list` for paginated threads through the thread store,
  preserving cursors, sort direction, turn status, timing, errors, and the
  requested `summary` or `notLoaded` item view.
- Reject the `full` turn item view for paginated threads and direct clients to
  `thread/items/list` for complete item pagination.
- Return each item page entry with both its containing `turnId` and `item`, so
  clients can regroup thread-wide pages into turns.
- Expose local thread-store turn and item pagination through the `ThreadStore`
  implementation.

## Testing

Added app-server coverage for paging projected turns and items, item views,
cursors, turn metadata, and rejection of the unsupported `full` view.

GitOrigin-RevId: 9c4a127a9b4fa91313f0e87494c62fe2e3a06f19
2026-07-14 20:48:05 +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
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
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
Eric Ning c71895f63b [codex] app-server: expose plugin install policy source (#31293)
## Summary

- Add `PluginInstallPolicySource` to the app-server v2 `PluginSummary`
payload.
- Propagate remote `installation_policy_source` through plugin
summaries, details, installed-plugin caching, and app-server responses.
- Preserve the supported source values and map unrecognized backend
values to `null`.
- Return `null` for local plugins and expose the field in generated JSON
and TypeScript schemas.
- Update app-server API documentation and plugin list/read coverage.

## Testing

- `just test -p codex-app-server-protocol` (251 passed)
- Targeted `codex-app-server` plugin list, installed, and read tests (4
passed)
- Targeted `codex-core-plugins` known and unknown policy source tests (2
passed)
- `just fmt`
- `git diff --check`
2026-07-06 17:12:39 -07:00
Eric Ning d206a5d68f [codex] expose remote plugin versions (#30981) 2026-07-03 17:14:49 -06:00
Owen Lin a107b84967 feat(protocol): define missing rollout turn items (#30282)
## Description

This PR adds canonical core `TurnItem` shapes for command execution,
dynamic tool calls, collab agent tool calls, and sub-agent activity, to
be stored in the rollout file soon.

It also teaches app-server protocol / `ThreadHistoryBuilder` how to
render those items, and adds the small legacy fanout helpers needed for
existing event-based consumers. No core producer or rollout persistence
behavior changes here, that will be done in a followup.

## Making ThreadHistoryBuilder stateless

This is the first PR in a stack to make `ThreadHistoryBuilder` stateless
enough that we can materialize app-server `ThreadItem`s from only a
given slice of `RolloutItem` history, without ever needing to replay the
whole thread from the beginning.

The persisted legacy `RolloutItem::EventMsg` records are mostly shaped
like live UI events, not like materialized `ThreadItem`s. They work if
we replay the full rollout in order, but they often do not contain
enough stable identity or complete item state to project an arbitrary
suffix on its own.

A few examples:

- `UserMessageEvent` and `AgentMessageEvent` have content, but
historically do not carry the persisted app-server item ID that should
become the SQLite primary key.
- `AgentReasoningEvent` and `AgentReasoningRawContentEvent` are
fragments. `ThreadHistoryBuilder` currently merges them into the last
reasoning item, which means a slice starting in the middle of reasoning
cannot know whether to append to an earlier item or create a new one.
- `WebSearchEndEvent`, `McpToolCallEndEvent`, collab end events, and
similar legacy events can often render a final-looking item, but they
usually rely on prior replay state to know which turn owns the item.
- Begin/end legacy events are partial views of one logical item. The
builder correlates them by `call_id` and mutates prior state to
synthesize the final `ThreadItem`.

That is the problem this direction fixes. A persisted canonical
lifecycle record looks much closer to the read model we actually want
later:

```rust
ItemCompletedEvent {
    turn_id,
    item: TurnItem { id, ...full snapshot... },
    completed_at_ms,
}
```

Once rollout has explicit `turn_id`, stable `item.id`, and a canonical
completed item snapshot, the future SQLite projector can reduce only the
new rollout suffix and upsert the affected `thread_items` rows. It no
longer needs to synthesize `item-N`, infer item ownership from the
active turn, or replay earlier events just to reconstruct the current
item snapshot.

## What changed

- Added core `TurnItem` variants and item structs for command execution,
dynamic tool calls, collab agent tool calls, and sub-agent activity.
- Added conversions from those canonical items back into the legacy
event shapes where current consumers still need them.
- Added app-server v2 `ThreadItem` conversion for the new core item
variants.
- Taught `ThreadHistoryBuilder` and rollout persistence metrics to
recognize the new item variants.

## Follow-up

The next PR https://github.com/openai/codex/pull/30283 switches the live
core producers for these item families onto canonical `ItemStarted` /
`ItemCompleted` events.
2026-06-26 16:44:34 -07:00
charlesgong-openai 6509f3148a [codex] Support npm marketplace plugin sources (#29375)
## Why

Marketplace source deserialization treated `{"source":"npm", ...}` as
unsupported. The loader logged and skipped the entry, so npm-backed
plugins never appeared in `plugin list --available` and `plugin add`
returned "plugin not found".

Codex plugins are installed from a plugin root, not from an npm
dependency tree. For npm-backed marketplace entries, Codex should fetch
the published package contents without running package scripts or
installing unrelated dependencies.

## What changed

- Add `npm` marketplace plugin sources with `package`, optional semver
`version` or version range, and optional HTTPS `registry`.
- Reject unsafe npm source fields before materialization, including
invalid package names, non-semver version selectors, plaintext or
credential-bearing registry URLs, and registry query/fragment data.
- Materialize npm plugins with `npm pack --ignore-scripts`, then unpack
the resulting tarball through the existing hardened plugin bundle
extractor.
- Enforce npm archive and extracted-size limits, require the standard
npm `package/` archive root, and verify the extracted `package.json`
name matches the requested package before installing.
- Keep plugin listings, install-source descriptions, CLI JSON/human
output, app-server v2 `PluginSource`, TUI source summaries, regenerated
schema fixtures, and app-server documentation in sync.

## Impact

Marketplaces can distribute Codex plugins from public or configured
private HTTPS npm registries using the same install flow as existing
materialized plugin sources. `npm` must be available on `PATH` when an
npm-backed plugin is installed.

Fixes #27831

## Validation

- `just write-app-server-schema`
- `just test -p codex-core-plugins -p codex-app-server-protocol -p
codex-app-server -p codex-cli`
  - npm/schema/core-plugin coverage passed in the run.
- The full focused command finished with `1739 passed`, `11 failed`, and
`6 timed out`; the failures were unrelated local app-server environment
failures from `sandbox-exec: sandbox_apply: Operation not permitted`
plus one missing `test_stdio_server` helper binary.
- Installed an npm-published Codex plugin package through a throwaway
local marketplace and throwaway `CODEX_HOME` to exercise the real npm
materialization path end to end.
2026-06-26 17:24:46 -04:00
Owen Lin f72976a5f1 feat(app-server): add optional turn_id to thread/fork (#30277)
## Description

This adds stable optional `turnId` support to `thread/fork`. When
supplied, the fork copies persisted history through that terminal turn,
inclusive, and drops later turns from the new thread.

Omitting or passing `null` preserves the existing full-history fork
behavior, including the interruption marker when the stored source
history ends mid-turn.

## Why

We're deprecating `thread/rollback` and this will help certain UX use
cases work around it by using `thread/fork` + `turn_id` instead.
2026-06-26 19:35:54 +00:00
hefuc-oai d9cf931d0e [codex] Add managed new-thread model settings (#29683)
## Why

Admins need persistent defaults for the model, reasoning effort, and
service tier shown when the Desktop App creates a new thread. These are
initialization defaults rather than runtime constraints: the App should
use them to initialize its draft while still allowing a user to make an
explicit selection.

The app-server therefore needs to expose the managed values before
thread creation without changing `thread/start` behavior for other
clients.

## What changed

- Parse `model`, `model_reasoning_effort`, and `service_tier` from
`[models.new_thread]` in `requirements.toml`.
- Compose the `models` requirements through the existing
requirements-layer precedence rules.
- Expose the resolved values through `configRequirements/read` as
`requirements.models.newThread`.
- Add the corresponding app-server protocol types and regenerate the
JSON and TypeScript schema fixtures.
- Document the new `configRequirements/read` fields in the app-server
README.

## Scope

This PR is data plumbing only. It does not apply these values during
`thread/start` and does not change thread creation for existing
app-server clients, resumed or forked sessions, internal or subagent
sessions, `codex exec`, or the TUI. A companion Desktop App change owns
draft initialization, sends the effective settings for ordinary and
prewarmed starts, and preserves explicit user changes.

## Validation

- Requirements deserialization coverage for `[models.new_thread]`
- Requirements-layer precedence coverage
- App-server API mapping coverage
- `configRequirements/read` integration coverage
- Regenerated app-server JSON and TypeScript schema fixtures
2026-06-26 18:37:40 +00:00
Owen Lin 5267e805fb feat(app-server): add history_mode to thread (#29927)
## Description

This PR adds a new `historyMode = "legacy" | "paginated"` to `Thread`.
This will be stored in `SessionMeta` in the JSONL rollout file and as a
new column in the SQLite thread_metadata table, and exposed on
`thread/start` and on the `Thread` object in app-server.

## What changed

- Added canonical `ThreadHistoryMode` with `legacy` and `paginated`,
defaulting old and new SessionMeta to `legacy`.
- Carried `history_mode` through core session config, ThreadStore stored
metadata, local/in-memory stores, rollout metadata extraction, and the
existing SQLite `threads` table.
- Added experimental `historyMode` to app-server v2 `Thread` and
`thread/start`.
- Made paginated stored threads metadata-discoverable but unsupported
for legacy full-history reads, `load_history`, live resume, and create
paths.
- Regenerated app-server schema fixtures and added
protocol/state/thread-store/app-server coverage for persistence and
fail-closed behavior.

## Compatibility floor
Because users may be running various versions of Codex binaries on the
same machine (TUI, Codex App, etc.), we will need to establish a
compatibility floor for upcoming paginated threads, which will change
how thread storage reads and writes work.

The overall plan here:
```
Release N:
- Add historyMode to SessionMeta / Thread / SQLite metadata.
- Teach binaries to understand paginated threads.
- If a binary sees `historyMode="paginated"` but does not support the paginated contract, it refuses to resume/mutate the thread.
- Default remains `"legacy"`.

Release N+1:
- First-party clients start opting into paginated threads where appropriate.
- Internal dogfood / staged rollout.
- Measure old-client usage and paginated-thread unsupported errors.

Release N+2:
- Only after Release N+ is overwhelmingly deployed, make paginated the default.
- Accept that a small tail of N-1-or-older binaries may not understand paginated threads.
```

The important behavior change is fail-closed handling for a binary that
encounters a persisted `paginated` thread before it knows how to fully
support paginated history. In app-server, if a thread is `paginated`, we
will:

- allow metadata-only discovery paths like `thread/list` and
`thread/read(includeTurns=false)`, so clients can still see the thread
and inspect its `historyMode`
- reject legacy full-history/live-thread paths like
`thread/read(includeTurns=true)` and `thread/resume` with an unsupported
JSON-RPC error
- avoid silently treating an unknown or future `historyMode` as `legacy`

Under the hood, the ThreadStore layer also rejects legacy operations
that would need to load or replay the full thread history for a
paginated thread. That gives us the behavior we want for Release N:
future paginated threads are visible, but this binary fails closed
instead of trying to operate on them as if they were legacy threads.
2026-06-26 09:12:42 -07:00
Martin Au-YeungandMartin Au-Yeung ec300bc7bd Expose MCP app identity in app context (#29934)
## Why

MCP tool-call events need to expose trusted app identity and action
metadata directly so v2 clients do not have to infer it from tool names
or resource URIs.

## What changed

- Add optional `appName`, `templateId`, and `actionName` fields to MCP
tool-call `appContext`.
- Populate `appName` and `templateId` from trusted Codex Apps metadata,
and derive `actionName` from the trusted app resource metadata.
- Preserve all three fields through core events, legacy protocol events,
persisted thread history, resume redaction, and app-server v2 responses.
- Document the public `appContext` fields in
`codex-rs/app-server/README.md`.
- Regenerate app-server JSON and TypeScript schemas and add coverage for
serialization, persistence, redaction, and metadata propagation.

## Validation

- `just test -p codex-app-server-protocol mcp_tool_call`
- `just test -p codex-core
mcp_tool_call_item_metadata_only_trusts_codex_apps_identity
mcp_tool_call_item_includes_app_identity`
- `just write-app-server-schema`

---------

Co-authored-by: Martin Au-Yeung <280153141+martinauyeung-oai@users.noreply.github.com>
2026-06-25 18:31:10 -07:00
felixxia-oai a6d20ed297 [codex] Surface MCP reauthentication-required startup failures (#29877)
## Summary

- distinguish expired, non-refreshable stored MCP OAuth credentials from
first-time missing credentials
- carry a typed `failureReason: "reauthenticationRequired"` on the
existing `mcpServer/startupStatus/updated` notification only when user
action is required
- keep the public MCP auth-status API unchanged and regenerate the
app-server protocol schemas and documentation

## Why

An MCP server with an expired access token and no usable refresh token
currently fails startup without giving clients a reliable, typed
recovery signal.

The existing startup-status notification is the natural place to carry
this state. Its nullable `failureReason` keeps the recovery reason
attached to the failed startup transition without adding a one-off
notification. Internally, Codex distinguishes first-time login from
reauthentication and emits the reason only when the startup error itself
requires authentication.

## User impact

App clients can prompt an existing user to reconnect an MCP server when
automatic recovery is impossible by handling a failed
`mcpServer/startupStatus/updated` notification whose `failureReason` is
`reauthenticationRequired`. Starting, ready, cancelled, unrelated
failures, and first-time setup carry no reauthentication reason.

## Companion app PR

- openai/openai#1069582

## Validation

- `just test -p codex-app-server-protocol` — 248 passed; schema fixture
tests passed
- `cargo check -p codex-app-server -p codex-tui`
- `just test -p codex-rmcp-client -p codex-mcp` — 184 passed, 2 skipped
- `just test -p codex-protocol -p codex-app-server-protocol -p
codex-mcp` — 579 passed
- `just write-app-server-schema`
- `just fmt`
2026-06-25 21:50:36 +00:00
Owen Lin 1882719b30 feat(app-server): thread/turns/items/list -> thread/items/list (#29705)
## Description

Rename the experimental app-server item pagination API from
`thread/turns/items/list` to `thread/items/list` and make `turnId`
optional. Clients can now page persisted items across a thread, or still
filter to one turn when needed.

## What changed

- Rename the request/response protocol types and JSON-RPC method to
`ThreadItemsList*` / `thread/items/list`.
- Pass optional `turnId` through to `ThreadStore::list_items`.
- Update app-server docs and focused protocol/app-server tests.

## Validation

- `just test -p codex-app-server-protocol thread_items_list_round_trips`
- `just test -p codex-app-server thread_items_list_returns_unsupported`
2026-06-23 13:57:08 -07:00
Adam Perry @ OpenAI 510bce9927 core: resolve view_image paths in selected environment (#29526)
## Why

view_image needs to support foreign OS remote executors.

## What

- resolve image paths against the selected environment as `PathUri` and
read them through that environment's filesystem
- keep app-server's public path field wire-compatible as
`LegacyAppPathString`, with purpose-specific UI rendering
- cover relative and absolute target-native paths in the core
integration test and run the full `view_image` suite under wine-exec
without skips
2026-06-23 19:52:37 +00:00
Boyang Niu 354807920e core: add extra metadata field to Thread struct (#29675)
# Summary

Adds a field Thread.extras that can be used to hold arbitrary metadata
specific to a given thread.
2026-06-23 19:15:59 +00:00
Dylan Hurd 2cf2a6a844 chore(core) rm AskForApproval::OnFailure (#28418)
## Summary
Deletes the OnFailure variant of the `AskForApproval` enum. This option
has been deprecated since #11631.

## Testing
- [x] Tests pass
2026-06-23 12:13:54 -07:00
Drew 2c351cb864 [plugins] Add dark-mode logo metadata (#29488)
Adds additive dark-mode plugin logo metadata across manifests, remote
catalogs, and the app-server protocol while keeping uninstalled Git
listings free of synthetic local paths.

Supersedes #28945. This replacement uses an upstream branch so trusted
CI can use the repository-provided remote Bazel configuration.

## Current state

Plugin interfaces expose only the default logo asset. Clients therefore
cannot select a dedicated dark-mode logo even when a plugin provides
one.

## What this PR changes

- Adds nullable `logoDark` and `logoUrlDark` fields to
`PluginInterface`.
- Resolves local `interface.logoDark` assets and maps remote
`logo_url_dark` values.
- Removes path-backed interface assets, including `logoDark`, from
uninstalled Git fallback listings until the plugin has a real local
root.
- Updates the bundled plugin validator and manifest reference.
- Regenerates the app-server JSON schemas and TypeScript types.

Local manifests expose `interface.logoDark` as a package-relative asset
path. Remote catalog responses expose `logo_url_dark`. These values map
into separate app-server fields so clients can preserve local-path and
remote-URL handling.

## Risk

The fields are additive and nullable, so existing clients retain their
current logo behavior. The main risks are an incomplete mapping path or
exposing a synthetic local path for an uninstalled Git plugin.
Local-manifest, remote-catalog, fallback-listing, protocol
serialization, and app-server integration tests cover those paths.

Spiciness: 2/5

## Testing

- `just write-app-server-schema`
- `just fmt`
- Regression test first failed with `logo_dark` resolved to
`/assets/logo-dark.png`, then passed after the fallback-listing fix.
- `just test -p codex-core-plugins` (267 tests passed)
- `just test -p codex-app-server 'suite::v2::plugin'` (114 tests passed)
- `just test -p codex-app-server-protocol -p codex-core-plugins -p
codex-plugin -p codex-skills` (517 tests passed before the follow-up)
- `just test -p codex-tui plugin` (47 tests passed)
- Validated a local plugin manifest containing `interface.logoDark` with
the bundled validator.

## Manual verification

Create a local plugin with both `interface.logo` and
`interface.logoDark`, then call `plugin/list` or `plugin/read`. Confirm
the response contains separate `logo` and `logoDark` paths. For a remote
catalog entry, confirm `logoUrlDark` is populated from `logo_url_dark`.
For an uninstalled Git marketplace entry, confirm path-backed interface
assets remain absent until installation.

Issue: N/A - coordinated maintainer change.
2026-06-22 16:01:27 -07:00
jif c03742ca0a Simplify multi-agent mode controls (#29324)
## Why

Multi-agent delegation policy was split across `multiAgentMode`,
`features.multi_agent_mode`, and `usage_hint_enabled`. These controls
could disagree: a requested mode could be downgraded by the feature
flag, and disabling usage hints also disabled mode instructions.

Some clients also need multi-agent tools without adding
delegation-policy text to model context. The previous two-mode API could
not express that directly.

## What changed

`multiAgentMode` is now the only live delegation-policy control:

| Mode | Behavior |
| --- | --- |
| `none` | Keep multi-agent tools available without adding mode
instructions. |
| `explicitRequestOnly` | Only delegate after an explicit user request.
|
| `proactive` | Delegate when parallel work materially improves speed or
quality. |

- new threads default to `explicitRequestOnly`; omitting the mode on
later turns keeps the current value
- thread start, resume, fork, and settings responses always report the
concrete current mode instead of `null`
- mode selection remains sticky across turns and resume
- usage-hint text no longer controls whether mode instructions apply
- `features.multi_agent_mode` and `usage_hint_enabled` remain accepted
as ignored compatibility settings so existing configs continue to load
- app-server documentation and generated schemas describe the three-mode
API

## Tests

- `just test -p codex-core multi_agent_mode`
- `just test -p codex-core multi_agent_v2_config_from_feature_table`
- `just test -p codex-core spawn_agent_description`
- `just test -p codex-features`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server multi_agent_mode`
2026-06-22 10:05:36 +02:00
Shijie Rao 7abfcf220b Expose thread-level multi-agent mode (#28792)
## Why

Once multi-agent mode can be selected per turn, clients also need to
choose the initial selection when creating a thread and observe that
selection through lifecycle and settings APIs.

The selected value is intentionally distinct from the effective
model-visible value: no client selection is represented as `null`, even
though an eligible multi-agent v2 turn derives `explicitRequestOnly` as
its effective default.

## What changed

- Add the optional experimental `thread/start.multiAgentMode` parameter
and pass it through thread creation.
- Preserve an omitted initial value as an unset selection rather than
eagerly storing `explicitRequestOnly`.
- Apply an explicit `thread/start` selection to the first turn through
the session configuration established at thread creation.
- Restore the latest persisted effective mode as the selected baseline
on cold resume when rollout history contains one.
- Inherit the optional selected mode from a loaded parent when creating
related runtime threads.
- Return the current selected `multiAgentMode` from `thread/start`,
`thread/resume`, `thread/fork`, and thread settings, using `null` when
no mode is selected.
- Keep lifecycle reporting independent from model capability and feature
eligibility; core turn construction remains responsible for calculating
and persisting the effective mode.

## Not covered

- Clearing an existing loaded-session selection back to unset through
`turn/start`; omitted or `null` currently retains the session's
selection.
- A TUI control, slash command, or `config.toml` preference.

## Verification

- `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol`
- `CARGO_INCREMENTAL=0 just test -p codex-app-server multi_agent_mode`

The focused app-server coverage verifies explicit `thread/start`
initialization, first-turn prompting, nullable reporting for an omitted
selection, and retention of selections that are not currently
runtime-eligible.

## Stack

Stacked on #28685. This PR contains only the thread initialization and
lifecycle/settings API layer.
2026-06-19 10:50:44 +02:00
Shijie Rao fc8c6b7384 Add per-turn multi-agent mode (#28685)
## Why

Multi-agent v2 currently carries an explicit-request-only delegation
rule in its static usage hint. That provides a safe default, but it
prevents clients from selecting proactive delegation per turn without
changing static guidance or rewriting prior model context.

This change makes delegation mode a session selection that can be
updated through `turn/start`, while deriving the effective model-visible
mode separately for each turn. Eligible multi-agent v2 turns remain
explicit-request-only unless proactive mode is both selected and
enabled.

## What changed

- Add the experimental `turn/start.multiAgentMode` parameter with
`explicitRequestOnly` and `proactive` values. Omission retains the
loaded session's current optional selection.
- Add the default-off `features.multi_agent_mode` feature gate. Eligible
multi-agent v2 turns use the selected mode when enabled; an unset
selection or disabled gate resolves to `explicitRequestOnly`.
- Treat mode prompting as inapplicable for multi-agent v1 and other
unsupported session configurations, producing no multi-agent mode
developer message rather than rejecting the turn.
- Move the explicit-request-only rule out of the static v2 usage hint
and into a bounded, tagged developer context fragment.
- Emit the effective mode in initial context and only when that
effective mode changes on later turns.
- Persist the effective mode in `TurnContextItem` as the durable
baseline for resume and context-update comparisons.

Historical rollout items are not rewritten. Later mode developer
messages establish the current rule incrementally.

## Not covered

- Initial selection through `thread/start` and selected-mode reporting
from thread lifecycle/settings APIs; those are isolated in the stacked
#28792.
- A TUI control or slash command for selecting the mode.
- Persisting a preferred mode to `config.toml`; selection remains
session/turn scoped.
- Changes to multi-agent concurrency limits, tool availability, or model
catalog capability declarations.
- Rewriting historical rollout prompt items. Cold resume restores the
latest persisted effective mode when available while leaving historical
developer messages intact.

## Verification

- `CARGO_INCREMENTAL=0 just test -p codex-core multi_agent_mode`
- Focused app-server coverage verifies that `turn/start.multiAgentMode`
produces proactive developer instructions for an eligible v2 turn.

## Stack

Followed by #28792, which adds `thread/start` initialization and
lifecycle/settings observability.
2026-06-18 22:47:51 -07:00
Adam Perry @ OpenAI dce673905a core: load AGENTS.md from foreign environments (#28958)
## Why

Make it possible to load AGENTS.md from remote exec-servers whose OS is
different than app-server.

## What

- keep `AGENTS.md` discovery and provenance as `PathUri`, with
root-aware parent and ancestor traversal
- expose lifecycle instruction sources as legacy app-server path strings
in events while retaining `PathUri` internally
- preserve and test mixed POSIX and Windows paths in model context and
TUI status output
- cover remote Windows loading end to end by seeding the Wine prefix
through host filesystem APIs
- fix bug in `PathUri`'s parent() implementation that would erase
Windows drive letters
2026-06-18 15:06:23 -07:00
martinauyeung-oaiandmartinauyeung-oai 765309d5a6 Emit Trusted MCP App Identity on Tool-Call Items (#27132)
## Summary

- Add optional `appContext` to app-server MCP tool-call items with
trusted `connectorId`, `linkId`, and `mcpAppResourceUri` metadata.
- Preserve that context across tool-call events, persisted history,
reconnects, and thread resume.
- Keep the deprecated top-level `mcpAppResourceUri` temporarily for
client migration.

The consumer contract is `{ appContext: { connectorId, linkId,
mcpAppResourceUri }, tool }`.

## Validation

- Full GitHub Actions suite passes, including CLA, Bazel tests, clippy,
release builds, and argument-comment lint.

---------

Co-authored-by: martinauyeung-oai <280153141+martinauyeung-oai@users.noreply.github.com>
2026-06-18 14:02:54 -07:00
Gabriel Peal 21a599fa56 Support openai/form extended form elicitations (#27500)
# Summary
Allow App Server clients to opt into `openai/form` MCP elicitations.
2026-06-18 11:54:49 -07:00
charlesgong-openai 3959ab0ffc [codex] Track plugin install and import telemetry failures (#28731)
## Summary
- Track plugin install failures through the unified
`codex_plugin_install_failed` event for local installs, remote install
preflight failures, bundle failures, and remote catalog/backend
failures.
- Send classified `error_type` values in plugin install failure
analytics instead of raw error strings.
- Stop sending raw external-agent import errors in analytics while
preserving raw failure details in app-facing import
notifications/history.
- Keep raw plugin/migration diagnostics in `tracing::warn!` logs.
- Keep remote failure plugin names as the existing local placeholder
(`unknown`) and remove the extra telemetry plugin-name override.
- Change `ExternalAgentConfigImportParams.source` from a generated enum
to `string | null`, with legacy `claudeCode` / `claudeCowork` inputs
normalized to existing analytics values.

## Testing
2026-06-17 13:16:34 -07:00
Jeremy Rose 7dc7096ae1 [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.
2026-06-17 18:52:18 +00:00
pakrym-oai cb15c64760 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.
2026-06-16 21:39:30 -07:00
Jeremy Rose fac3158c2a 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
2026-06-16 17:06:22 -07:00
Adam Perry @ OpenAI f8850cab1d 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`
2026-06-16 21:42:28 +00:00