Commit Graph
44 Commits
Author SHA1 Message Date
Brent Traut 47c063de51 Add experimental thread item lookup by ID (#52637)
## What changed

Add `thread/items/read` to retrieve persisted items by `threadId`, `turnId`, and 1–100 `itemIds`. Return matching items in canonical stored order, omitting missing IDs and items outside the requested turn.

Add item ID filtering to the thread store while preserving inherited history and fork cutoffs. Require the experimental API capability for the new endpoint.

## Testing

Add coverage for stored ordering, turn scoping, missing IDs, request size limits, experimental capability gating, and inherited items across fork cutoffs.

GitOrigin-RevId: 9b243dd87577bd4fe36900c388a386b2e26ff2e0
2026-10-09 16:50:24 +00:00
jif 946bb6c583 Finish idle thread unloads after slow shutdown (#51420)
## Why

Idle thread unloading stopped waiting after ten seconds, leaving the thread loaded when resource cleanup took longer.

## What changed

Keep awaiting the same shutdown future after the ten-second deadline, emitting `codex.app_server.thread_shutdown_slow` as a warning. Once shutdown completes, remove the thread and send `thread/closed` without requiring another unload request.

## Testing

Add a regression test that blocks writer-lock cleanup past the warning deadline, verifies the thread remains loaded while cleanup is blocked, then releases the lock and checks for `thread/closed` and an empty loaded-thread list.

GitOrigin-RevId: 18c411f86fd69e710e472a4e3572d75f18682147
2026-10-06 17:10:19 +00:00
jif 595534314f Use descriptor-safe helpers for executable test fixtures (#50018)
## Why

Concurrent Linux test spawns can inherit writable descriptors for executable fixtures, preventing those fixtures from being executed even after the writing test closes its descriptor.

## What changed

Replace direct executable fixture writes and copies across the Rust tests with `codex_utils_cargo_bin::write_executable` and `copy_executable`. These existing helpers complete writes and copies in separate processes on Linux.

Remove the empty temporary inode before creating fake bubblewrap executables, and stage tampered bubblewrap bytes in a separate data file before copying them into the executable fixture. Add the required test dependencies.

GitOrigin-RevId: c875c83088731a4933ef1574e8d79d8cecc12f54
2026-10-01 15:57:03 +00:00
acrognale-oai a4354e2d27 Expose selected workspace routing in app-server account reads (#45529)
## What changed

- Add experimental `account/read.workspaceRouting` metadata containing the selected ChatGPT workspace ID, resolved HTTPS backend origin, and routing override (`us`, `us_cr`, or `NO_CONSTRAINT`).
- Discover and cache routing through `accounts/check` for saved logins, new logins, and workspace switches. Return `null` for signed-out accounts, API-only accounts, and saved credentials without a selected workspace.
- Validate discovered origins against required `chatgpt_base_url` origins. Return errors for failed or malformed discovery and retry on later reads.
- Wait for requirements and routing before publishing account updates, including to newly initialized connections. Clear routing on logout, discard stale discovery results, and guard queued notifications against account changes.

## Testing

Add unit and integration coverage for origin resolution and validation, discovery failures and retries, startup discovery, workspace switching, logout, configuration changes during discovery, and authentication changes while notifications wait for queue capacity.

GitOrigin-RevId: 2c5367bb01dd7543b08d374f44444323e40f1981
2026-09-14 22:31:32 +00:00
Owen Lin 3052bbcf8c Remove the deprecated thread/rollback API (#44915)
## What changed

Remove `thread/rollback`, its request and response types, generated bindings, and the core `Op::ThreadRollback` operation. Requests now follow the generic unknown-method rejection path. Document `thread/revert` as the alternative for paginated threads.

Keep historical `ThreadRolledBack` markers and legacy error deserialization so existing rollouts remain compatible with replay and migration.

## Testing

Adapt retained-context and Guardian history tests to append legacy rollback markers and resume threads, preserving coverage of surviving instructions, answers, and review history.

GitOrigin-RevId: b3da1becdf86b1869275aacb0ffc2817cee5af2e
2026-09-11 21:32:04 +00:00
jif 713caa89f3 Bound app-server stdio shutdown and handle Unix SIGTERM gracefully (#44523)
## Why

Stdio shutdown can hang on open pipes or blocked I/O, and Unix `SIGTERM` needs to run connection cleanup so owned commands terminate and session-end hooks execute.

## What changed

- Handle `SIGTERM` on a dedicated signal thread and close the stdio connection through the existing cleanup path.
- Move blocking stdin and stdout operations to dedicated threads so they do not hold the Tokio runtime open. Cancel message forwarding on `SIGTERM` to release blocked producers.
- When shutdown signal handling is enabled on Unix, start a shared 45-second watchdog on EOF or `SIGTERM`. Preserve the first deadline and exit with status `1` if cleanup or runtime teardown stalls, even when logging is blocked.

## Testing

Add Unix integration coverage for shutdown with open pipes, blocked stdout, blocked stderr, and a stalled filesystem write. Verify command and child-process termination, preserve the EOF deadline when `SIGTERM` follows, and extend session-end hook coverage to `SIGTERM`.

GitOrigin-RevId: 43a80b8277eb50519cdc293eb3b5dc2cad00b3aa
2026-09-10 13:02:57 +00:00
jif 531f3836a1 Remove the deprecated codex mcp-server command (#42993)
## What changed

Remove the `codex mcp-server` subcommand and the standalone `codex-mcp-server` crate, including its tests, interface documentation, build dependencies, and run recipe.

## Testing

Update the strict configuration test to use `codex exec hello`, preserving coverage for rejecting unknown configuration overrides.

GitOrigin-RevId: 8688b1f41862d7c2073ea2812a257c0087c55d9c
2026-09-05 12:17:32 +00:00
Chris Hayduk c9fac4dd5a Avoid holding metadata permit during cold resume config load (#42773)
## Why

Cold `thread/resume` configuration loading can call back into the host. Holding the global metadata permit during that work blocks unrelated thread metadata updates and MCP requests.

## What changed

- Release the metadata permit while loading configuration for a cold resume.
- Reacquire the permit and reload the resolved thread history before startup.
- Reload configuration when persisted metadata, settings, or the history working directory changed during the unlocked interval.
- Rejoin a thread that another request resumed concurrently, and avoid reopening threads that were archived or deleted.

## Testing

Add coverage for unrelated metadata and MCP requests during a blocked config load, concurrent resume mutations, and the extra history read required for non-local thread stores.

GitOrigin-RevId: 8cbd3868eeff84968765b1e3dbc7590ebe5fa892
2026-09-04 14:23:27 +00:00
joeflorencio-openai 9695e71519 Add turn-scoped settings updates to the app server (#40656)
## What changed

- Add the experimental `turn/settings/update` method for changing `model`,
  `effort`, `summary`, and `serviceTier` on a specific live turn without
  changing future turns.
- Report whether the update was applied or the target turn was unavailable,
  and reject unsupported fields, disabled feature use, unsafe model changes,
  and direct updates to parent-owned subagents.
- Document the method's feature requirements, null handling, and limits.

## Testing

- Cover current-turn and future-turn isolation, rejected and unavailable
  targets, feature and capability gates, saved threads, and subagent ownership.

GitOrigin-RevId: 18440f6d7ee5fcd06ae23bd41b22c492b62bb2b5
2026-08-25 17:55:50 +00:00
guinness-oai 41ca88e95c Persist realtime events in the thread timeline (#40508)
## Why

Clients need a bounded view of realtime conversations that preserves the order of speech, agent work, and turn lifecycle events without loading the full thread history.

## What changed

- Persist realtime session boundaries, transcript segments, and promoted agent items in paginated thread rollouts.
- Add the experimental `thread/timeline/list` API to page ordinary items, realtime items, and turn boundaries in canonical rollout order. Include `activeRealtimeSessionAtPageStart` so each page can be rendered independently.
- Emit typed `thread/realtime/item/started`, `thread/realtime/item/transcript/delta`, and `thread/realtime/item/completed` notifications around durable realtime items.
- Keep the existing `thread/items/list` response and legacy thread history behavior unchanged.

## Testing

- Cover mixed timeline pagination, realtime-session state at page boundaries, rollout replay, subagent history prefixes, transcript streaming, steering, and promoted agent artifacts.

GitOrigin-RevId: faa2c420192d63e060e8fb32446e3c797422656e
2026-08-25 01:03:20 +00:00
Anton Panasenko 3b4569a920 Add experimental app-server project APIs (#38940)
## What changed

- Add SQLite-backed `project/list`, `project/read`, `project/create`,
  `project/import`, `project/update`, `project/move`, and `project/delete`
  endpoints with ordered roots, metadata, manual positioning, pagination, and
  idempotent creation.
- Add project assignment to thread start, metadata updates, list filtering,
  and fork inheritance. Project deletion clears assignments without deleting
  threads.
- Emit `project/changed` and `thread/project/updated` notifications after
  committed changes, and export the new protocol schemas and TypeScript types.

## Testing

- Cover project lifecycle and ordering, idempotency, atomic imports, cursor and
  filter validation, thread assignment, deletion, and fork inheritance.

GitOrigin-RevId: 47ae621be01ab8ef70a74a629fb29a5c5709ea33
2026-08-17 04:01:37 +00:00
jif 9afb96faff Retry busy app-server test executable spawns (#37354)
## Why

App-server integration tests can encounter a transient `ExecutableFileBusy`
error while starting their server process.

## What changed

Retry that specific spawn failure up to twice with a 10 ms delay, while
returning all other spawn errors immediately.

GitOrigin-RevId: 0982a9fe66bae4c41f556c845d12fb515dbf752c
2026-08-07 02:06:40 +00:00
jif a9da0bdbac Stage Bazel app-server test binaries in TEST_TMPDIR (#37343)
## Why

Bazel test binaries can reside on a different filesystem from the default
temporary directory, forcing executable staging to fall back from hard links to
expensive copies.

## What changed

Create the app-server test install layout under Bazel's `TEST_TMPDIR` when it is
set. Continue using the default temporary directory outside that environment.

GitOrigin-RevId: 63172fbf913ddba06c7b9543b5bf0fea249c903c
2026-08-07 00:46:23 +00:00
Greg Brisebois 64b2a3008e Declare the experimental plugin search API (#36402)
## What changed

- Add the experimental `plugin/search` request with search term, scope, working-directory, cursor, and limit parameters.
- Define paginated results that include each plugin's marketplace name and optional local marketplace path.
- Route the request through app server while returning method-not-found until the search implementation is available.

## Testing

- Add an app-server test that verifies `plugin/search` returns JSON-RPC error `-32601` with the expected not-implemented message.

GitOrigin-RevId: 755400468331f0887f7da7d933195c347aadf6d0
2026-07-31 23:08:55 +00:00
Channing Conger 97576b1794 Run code mode exclusively through the standalone host (#36217)
## What changed

- Move the V8 implementation into a dedicated `codex-code-mode-runtime` crate used by `codex-code-mode-host`, removing the embedded runtime fallback from the Codex process.
- Resolve the host executable from the active installation layout and check its availability before selecting tools.
- Fall back to direct tools with a one-time warning when optional code mode is unavailable. Keep `code_mode_only` and `disable_in_process_fallback` configurations fail-closed.

## Testing

- Cover host discovery for standalone and package layouts, including missing hosts and symlinks.
- Verify direct-tool fallback, one-time warnings, and fail-closed code-mode-only behavior.

GitOrigin-RevId: 5aa3c6f1db148b2231fc24089a2ee0e2b00dbddb
2026-07-30 20:24:29 +00:00
joeytrasatti-openai ad6fc66b6d Add persisted manual ordering for thread sections (#36007)
## What changed

- Add `thread/section/move` to atomically move a thread into, within, or out of a section. Threads can be inserted before an existing member or appended, and moves within a section preserve `sectionEnteredAt`.
- Add `section_position` sorting to `thread/list`, with ascending order as its default, and expose `sectionEnteredAt` in thread responses.
- Persist section positions and entry times in SQLite, including migration of existing section members into recency order. Section membership is no longer updated through `thread/metadata/update`.

## Testing

- Cover section moves, reordering, pagination, persistence across restarts and rollout reconciliation, concurrent updates, and rank renumbering.

GitOrigin-RevId: aec6d7ddedca5277029b5caf5c074975397e956c
2026-07-29 18:37:22 +00:00
jay 88eb3a2b8a Enable git attribution across Codex entry points (#34819)
## What changed

- Install the git attribution extension in the app server, MCP server, and `codex debug prompt-input` so authenticated workspace policy controls the commit and pull request attribution instructions sent to the model.
- Resolve attribution settings from the process-level ChatGPT base URL, independent of per-thread or per-tool configuration overrides.
- Treat git attribution as contextual developer content when mapping model events.

## Testing

- Cover policy fetch retries, workspace switches, rollbacks, cold thread resumes with legacy instructions, MCP tool calls, and prompt-debug output.

GitOrigin-RevId: 57d182c432c20d7c1c6c429057b6163c9f32088d
2026-07-22 20:23:35 +00:00
pakrym-oai 10cc57c95c Simplify app-server integration test setup (#34786)
## What changed

- Add typed helpers for initialized app-server instances, JSON-RPC requests,
  responses, notifications, and thread startup.
- Add a composable `MockResponsesConfig` builder while preserving the existing
  mock config writers.
- Migrate the app-server integration suite to the shared helpers, removing
  repeated request ID management, deserialization, initialization, and config
  assembly.

## Testing

- Add unit coverage for composing mock provider, feature, and extra config, and
  for compatibility of the existing mock config writer.

GitOrigin-RevId: 62da177c1d6e8299400de64bd6766567bf1ba3d8
2026-07-22 16:30:12 +00:00
Charlie Marsh 221a341029 Remove unused Rust helpers (#34345)
## What changed

- Remove unused APIs and test helpers across the Rust workspace.
- Route Linux sandbox test setup through the shared exec request path.
- Drop dependencies that became unnecessary after the cleanup.

GitOrigin-RevId: 48fd9b2b1575bad7add0819786b4d8ec88d8486f
2026-07-20 13:45:29 +00:00
Owen Lin c1862b8db4 Add occurrence search for paginated threads (#33907)
## What changed

- Add the experimental `thread/searchOccurrences` app-server method for case-insensitive literal search across visible user messages and final assistant messages without replaying the thread.
- Return paginated snippets with UTF-16 match ranges and `thread/turns/list` cursors for navigating to each matching turn.
- Index persisted item types to efficiently select searchable messages from paginated thread history.

## Testing

- Add an app-server integration test covering pagination, steering messages, final-answer selection, Markdown normalization, and UTF-16 offsets.

GitOrigin-RevId: e80160e0f83eb4e5db8de862307085093bee362b
2026-07-17 21:24:26 +00:00
Abhinav 7bd44085e1 Add SessionEnd hooks for thread teardown (#33895)
## What changed

- Add the `SessionEnd` hook event to hook configuration, protocol schemas, analytics, and the hooks browser.
- Run matching hooks for root threads during shutdown, including app-server archive, delete, idle unload, and graceful shutdown. Flush the transcript first and provide the session ID, transcript path, working directory, and `reason: "other"`.
- Keep teardown bounded: hook output is advisory, the default timeout is one second, configured timeouts are capped at three seconds, and async hooks run synchronously with a warning.

## Testing

- Cover transcript availability, matcher selection, timeout normalization, ignored control output, subagent exclusion, archive/delete ordering, and graceful shutdown of multiple loaded threads.

GitOrigin-RevId: 5d19a658677a137caf836ed5042dcb43f5eb6d1a
2026-07-17 19:58:56 +00:00
Matthew Zeng a238b753af Add an API for reading installed app runtime state (#33843)
## What changed

- Add `app/installed` to return each connector observed in the committed runtime tool snapshot, including its runtime name and effective `enabled` and `callable` state.
- Support evaluating thread-specific configuration with `threadId` and refreshing the hosted connector tool snapshot with `forceRefresh`.
- Preserve observed connector identities as disabled when global or workspace policy disables Apps, and retain the previous snapshot when a refresh fails.

## Testing

- Cover cached and forced reads, policy and configuration filtering, thread-specific configuration, snapshot refresh failures, and protocol serialization.

GitOrigin-RevId: f697b6fb501b7d329a169e947a1c1607806222fe
2026-07-17 15:23:35 +00:00
stevenlee-oai 726b6378d2 Add an app-server API for reading app metadata (#33651)
## What changed

- Add the experimental `app/read` request for fetching metadata for up to 100
  app IDs, with optional display-only tool summaries.
- Preserve first-request order while deduplicating IDs, and report unknown or
  unauthorized apps as partial misses.
- Cache metadata by backend and ChatGPT account/workspace identity, refetch
  metadata-only entries when tools are requested, and preserve cached records
  when a backend request fails.

## Testing

- Cover request serialization, ordering, deduplication, partial misses, caching,
  tool-summary refetches, backend failures, cache isolation, and the ID limit.

GitOrigin-RevId: 55fc3281d99291e76d6c4a581e8d11569d3cb1ac
2026-07-16 17:46:36 +00:00
Celia Chen 518085387b Support Amazon Bedrock login in the app server (#33170)
## What changed

- Handle experimental `account/login/start` requests with `type: "amazonBedrock"`.
- Validate the API key and Mantle region, persist the managed credential, select the `amazon-bedrock` model provider, and emit the standard login and account-update notifications.
- Reload configuration for account and authentication status reads so the newly selected provider is visible immediately, with the startup configuration as a fallback.
- Extend the app-server test client with an Amazon Bedrock login mode that redacts API keys from request logs.

## Testing

- Add app-server coverage for successful login, credential and provider persistence, notifications, refreshed account state, invalid inputs, conflicting configuration, forced ChatGPT login, external authentication, and configuration reload failure.

GitOrigin-RevId: bf3ae98375caee41e78d2cdc677127138184c17a
2026-07-14 21:28:39 +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
pakrym-oai 4472698728 Support pending remote environment registration (#32231)
## Why

Remote environment provisioning can finish after a thread starts, before an
exec-server WebSocket URL is available.

## What changed

- Add `EnvironmentManager::register_pending_environment` and a one-shot
  `PendingEnvironmentRegistration` handle that resolves to either a validated
  WebSocket URL or a terminal provisioning error.
- Let lazy remote exec-server clients wait for that result, while preserving
  reconnection behavior after a successful registration.
- Keep replacement registrations isolated so completing an older handle does
  not resolve the current environment with the same ID.

## Testing

Add coverage for successful connection and reconnection, provisioning and
dropped-registration failures, invalid URLs, replacement isolation, and the
deferred-executor startup flow.

GitOrigin-RevId: 5c05be2b72291b77a1f71176d7075b1ad63332a5
2026-07-10 18:08:35 +00:00
Adam Perry @ OpenAI 3fa90665fe test: add delayed exec-server transport (#31427)
## Why

Macrobenchmarks benefit from having a way to exercise remote-executor
latency without depending on Docker.

This is a very minimal first cut, if we find that simulating network
conditions is useful we can always expand this scope or switch to a more
robust network shaping approach.

## What

- add a package-local exec-server binary for Cargo and Bazel test
fixtures
- add a host-local WebSocket exec-server fixture and fixed-delay
interposer
- let TestAppServer route its auto environment through that delayed
WebSocket transport
- cover the delayed thread/start path through the public app-server API

## Stack

1. [#31425 test: add TestAppServer
builder](https://github.com/openai/codex/pull/31425)
2. [#31427 test: add delayed exec-server
transport](https://github.com/openai/codex/pull/31427)
3. [#31295 bench: add cold skill load
macrobenchmark](https://github.com/openai/codex/pull/31295)
4. [#31428 bench: add e2e benchmark
entrypoints](https://github.com/openai/codex/pull/31428)
5. [#31429 ci: smoke Bazel e2e
benchmarks](https://github.com/openai/codex/pull/31429)
2026-07-09 00:17:38 +00:00
Channing Conger 9c6715924b code-mode: move to hosted mode by default (#31500)
## Summary

  - Promote code_mode_host to stable and enable it by default.
- Preserve features.code_mode_host = false as an opt-out to the
in-process runtime.
  - Run core code-mode tests through the standalone host.
  - Keep explicit coverage for missing-host failures.
2026-07-08 11:06:58 -07:00
Adam Perry @ OpenAI f73a072246 test: remove TestAppServer constructors (#31452)
## Why

Finish the TestAppServer builder migration after every caller has moved
off the compatibility constructors.

## What

- remove the obsolete public TestAppServer constructors
- leave TestAppServer::builder() as the only fixture construction API

## Validation

- cargo check -p codex-app-server --tests

## Cleanup stack

1. [#31425 test: add TestAppServer
builder](https://github.com/openai/codex/pull/31425)
2. [#31451 test: migrate TestAppServer callers to
builder](https://github.com/openai/codex/pull/31451)
3. this PR
2026-07-08 17:50:18 +00:00
Adam Perry @ OpenAI 922249310f test: add TestAppServer builder (#31425)
## Why

Test callers need one composable way to create app-server fixtures
instead of a growing family of overlapping constructor implementations.

## What

- add a feature-complete TestAppServer::builder()
- make the default builder own a temporary CODEX_HOME and select the
automatic test environment
- expose builder knobs for no automatic environment, explicit
CODEX_HOME, program, arguments, plugin startup tasks, environment
overrides, managed config, and JSON logging
- keep the existing public constructor surface, but route every
constructor through the builder so the new path is exercised immediately
- remove the redundant private constructor ladders; caller migration and
public constructor removal live in the optional cleanup stack

## Validation

- just test -p codex-app-server (940/941 before updating the expected
builder error wording)
- just test -p codex-app-server
auto_env_rejects_explicit_environment_config
- just fix -p codex-app-server
- just fmt

## Follow-up stacks

Cleanup, optional for the benchmark work:

1. [#31451 test: migrate TestAppServer callers to
builder](https://github.com/openai/codex/pull/31451)
2. [#31452 test: remove TestAppServer
constructors](https://github.com/openai/codex/pull/31452)

Benchmark infrastructure:

1. [#31427 test: add delayed exec-server
transport](https://github.com/openai/codex/pull/31427)
2. [#31295 bench: add cold skill load
macrobenchmark](https://github.com/openai/codex/pull/31295)
3. [#31428 bench: add e2e benchmark
entrypoints](https://github.com/openai/codex/pull/31428)
4. [#31429 ci: smoke Bazel e2e
benchmarks](https://github.com/openai/codex/pull/31429)
2026-07-07 22:20:48 +00:00
rafael-jac 1fd0858e86 [login] support hosted success redirects (#28745)
## What

Adds an optional hosted login-success redirect path for app-server login
requests.

- Keeps the existing localhost success page as the default.
- Lets app-server callers opt into a hosted success page with an
optional protocol field.
- Persists credentials before redirecting to the hosted success page.
- Keeps org setup and existing CLI/device-code login flows on the local
success page.
- Accepts an optional typed `appBrand` value and forwards it to the
hosted page as `app_brand` so web can select the correct asset.
- Generates the app-server protocol schema updates for the new optional
fields.

## Why

This supports the hosted Codex login success page rollout without
changing existing login behavior by default. The Codex Apps frontend can
gate the opt-in with Statsig after the hosted web page.

## Rollout safety

- Old callers omit the new field and continue using localhost.
- New callers talking to old app-server builds remain safe because the
Codex Apps side treats the field as optional and defaults the flag off.
- Missing brand values default to Codex.
- The hosted redirect always uses the app-login source so the hosted
page can reopen Codex; the existing streamlined-login visual flag
remains separate.

## Validation

- `just fmt`
- `just fix -p codex-login -p codex-app-server-protocol -p
codex-app-server -p codex-app-server-test-client -p codex-tui`
- `just test -p codex-login`
- `just test -p codex-app-server-protocol`
- `just write-app-server-schema`
- `git diff HEAD --check`

The focused login and protocol run passed all 380 tests.

I also started the broader `just test -p codex-app-server`; it compiled
successfully, then many tests failed on this machine because spawned
test servers tried to use the ambient `/Users/rafaelj/.codex/sqlite`
state DB, which is read-only in this sandbox. I stopped that run after
confirming the failures shared that environment issue.
2026-07-07 19:48:05 +00:00
Adam Perry @ OpenAI 8a18312ee5 app-server: cover selected environments in integration tests (#29992)
## Why

Now that basic cross-OS app/exec support is wired up, it's time to clean
up the tech debt of the remote_env_windows test and make sure its test
logic is covered in more maintainable feature-specific tests.

## What

- Add focused app-server tests for target-native `AGENTS.md` sources and
content, plus shell and cwd context, while preserving explicit TODO
baselines for the remaining host-scoped metadata.
- Add a `TestAppServer` helper that waits for and returns the matching
typed turn completion.
- Remove redundant app-server coverage and dependencies from
`remote_env_windows` while retaining its exec and apply-patch smoke
coverage. A follow-up will remove these.

## Validation

- `just test -p codex-app-server`
- `bazel test //codex-rs/app-server:app-server-all-wine-exec-test
--test_output=errors`
- `bazel test //codex-rs/core/tests/remote_env_windows:smoke-test
--test_output=errors`
2026-07-07 00:42:43 +00: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
Adam Perry @ OpenAI 283bc4cf01 test: add app-server auto environment helper (#29746)
## Why

Start moving towards app-server tests defaulting to running against
remote & foreign OS executors. To do so we need a point of indirection
similar to core integration tests' `build_with_auto_env`, but with the
flexibility of letting tests control environment registration if they
need to.

## What

This adds:

- `TestAppServer::new_with_auto_env()` for constructing an app server
with a default environment defined by the test runner (e.g. bazel)
- `TestAppServer::auto_env_params()` for tests to easily acquire turn
env params tailored to the automatic environment
- `TestAppServer::send_thread_start_request_with_auto_env()` to make it
easy for tests to start a thread using the automatic environment

The above methods all fail if the test calling them has set up an
environment where the automatic environment configuration conflicts with
test-created state.

## Validation

Adds a couple of basic smoke tests to the app-server test suite.
Follow-ups will migrate more tests to use it.
2026-06-24 01:06:29 +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
guinness-oai 1d8ff89aa3 Add realtime speech append control (#27917)
## Why

Realtime voice harness tuning needs app-side control over what backend
Codex text is spoken. Backend orchestrator text is written for a reading
UI, so automatically speaking every preamble, progress update, or final
assistant message can make the realtime voice model too chatty.

For experimentation, clients need two simple controls: keep app/client
text-item injection on the existing item-create path, and add an
explicit speakable path that app code can call only when it wants
realtime to speak. Automatic Codex output also needs an opt-in way to
switch from the protocol's default speakable path to regular realtime
items, with a caller-provided prefix so prompt wording can be tuned
outside core.

The default remains unchanged: if a client omits the new start fields
and never calls `appendSpeech`, automatic backend output continues down
the existing speakable path for the selected realtime protocol.

## What Changed

- Adds experimental `thread/realtime/appendSpeech` for app-provided
speakable text.
- Keeps existing `thread/realtime/appendText` as the item-create API for
app-provided realtime text items.
- Adds `codexResponsesAsItems` / `codex_responses_as_items` on
`thread/realtime/start` to send automatic Codex responses with
`conversation.item.create` instead of the protocol's default speakable
output path.
- Adds `codexResponseItemPrefix` / `codex_response_item_prefix` so
clients can prepend experiment instructions to those automatic Codex
response items.
- Keeps literal `conversation.handoff.append` routing scoped to the v1
speakable path; v2 default speech uses its item/function-output plus
`response.create` behavior.
- Removes the earlier public silent-context API and hardcoded
silent-context prefix.
- Updates realtime tests to cover default automatic speakable behavior,
opt-in automatic item-create behavior, and explicit `appendSpeech`
behavior.

## Validation

- `cargo check -p codex-core -p codex-app-server -p codex-api`
- `just test -p codex-app-server realtime_conversation`
- `just test -p codex-core realtime_conversation` (50/51 passed in the
filtered parallel run; the lone failure passed when rerun in isolation)
- `just test -p codex-core
conversation_mirrors_assistant_message_text_to_realtime_handoff`
- `just test -p codex-api
e2e_connect_and_exchange_events_against_mock_ws_server`
- `just fix -p codex-core`
- `just fix -p codex-app-server`
- `cargo build -p codex-cli`
2026-06-15 16:15:58 -07:00
jay bef99f861b feat(app-server): expose rate-limit reset credits (#28143)
## Why

Codex users can earn personal rate-limit reset credits, but app-server
clients do not currently have an API for reading or redeeming them. This
adds the backend and protocol foundation used by the `/usage` TUI flow
in #28154.

## What changed

- Extend `account/rateLimits/read` with a nullable
`rateLimitResetCredits` summary sourced from the existing usage
response.
- Add backend-client and app-server support for consuming a reset with a
caller-generated idempotency key. A UUID is recommended, and clients
reuse the same key when retrying the same logical reset.
- Return only the consume `outcome`; clients refetch
`account/rateLimits/read` for updated window state.
- Document the response field and each consume outcome, and regenerate
the JSON and TypeScript schema fixtures.
- Clarify in `AGENTS.md` that new app-server string enum values use
camelCase on the wire.
- Update the existing TUI response fixture for the expanded protocol
shape.
- Add coverage for authentication, response mapping, backend failures,
consume outcomes, and request timeout behavior.

## Validation

- `just test -p codex-app-server-protocol` — 231 passed.
- `just test -p codex-backend-client` — 14 passed.
- Focused `codex-app-server` reset-credit tests — 5 passed.
- Focused `codex-tui` protocol response fixture test — passed.
- `just fix -p codex-backend-client -p codex-app-server-protocol -p
codex-app-server` — passed.
- `just fmt` — passed.
2026-06-15 21:54:01 +00:00
Anton Panasenko b9dc3b7a8b feat(app-server): enforce managed remote control disable (#27961)
## Why

Managed deployments need a reliable deny gate for remote control.
Persisted enablement and explicit startup requests currently remain able
to start the transport, while the removed `features.remote_control` key
is intentionally only a compatibility no-op.

This adds a dedicated requirement that administrators can use to force
remote control off without deleting the user's persisted preference.
Removing the requirement and restarting restores the prior choice.

## What Changed

- Added top-level `allow_remote_control` requirements parsing, sourced
layer precedence, debug output, and `configRequirements/read` exposure
as `allowRemoteControl`.
- Added a typed transport policy captured from the startup requirements
snapshot. Managed disable forces the initial state to disabled and
prevents enrollment, refresh, connection, and persisted-preference
mutation.
- Rejected every `remoteControl/*` RPC before parameter deserialization
with JSON-RPC `-32600` and `remote control is disabled by managed
requirements`.
- Preserved the existing disabled status notification and the previous
behavior when the requirement is `true` or omitted.
- Regenerated app-server protocol schemas and documented the new
requirement.

## Verification

- Confirmed all remote-control RPCs, including a malformed request,
return the managed-policy error while the initial status notification
remains `disabled`.
- Confirmed explicit ephemeral startup and persisted enablement make no
backend connection and leave the SQLite preference unchanged.
- Confirmed `allow_remote_control = true` does not enable or block
remote control and `configRequirements/read` returns
`allowRemoteControl: false` for the deny policy.

Related issue: N/A (managed-policy hardening).
2026-06-12 20:10:12 -07:00
Anton Panasenko d61dfeb23a feat(app-server): persist remote-control desired state (#27445)
## Why

Remote-control runtime enablement and persisted enrollment preference
were represented by separate flags. That made startup rehydration, RPC
persistence, and new-enrollment seeding race with one another, and it
did not cleanly distinguish runtime-only CLI or daemon starts from
durable app-server RPC changes.

## What Changed

- Replace the parallel enablement, seed, and rehydration flags with one
transport-owned `RemoteControlDesiredState`.
- Add nullable enrollment-scoped persistence and preserve existing
preferences during enrollment upserts.
- Rehydrate plain startup only after auth and client scope resolve,
without overwriting a concurrent RPC transition.
- Make ordinary `remoteControl/enable` and `remoteControl/disable`
durable while retaining `ephemeral: true` for runtime-only callers.
- Have the daemon explicitly request ephemeral enablement and regenerate
the app-server schemas.

## Verification

- Covered migration and `NULL`/`0`/`1` persistence round trips.
- Covered plain-start rehydration and runtime-only versus durable
enrollment seeding.
- Covered durable enable, durable disable, and ephemeral enable through
app-server RPC.
- Covered the daemon's exact `{ "ephemeral": true }` request payload.

Related issue: N/A (internal remote-control persistence architecture
change).
2026-06-11 21:28:52 -07:00
Eric Traut a19d43a40a Add app-server thread/delete API (#25018)
## Why

Clients can archive and unarchive threads today, but there is no
app-server API for permanently removing a thread. Deletion also needs to
cover the full session tree: deleting a main thread should remove
spawned subagent threads and the related local metadata instead of
leaving orphaned rollout files, goals, or subagent state behind.

## What

- Adds the v2 `thread/delete` request and `thread/deleted` notification,
with the response shape kept consistent with `thread/archive`.
- Implements local hard delete for active and archived rollout files.
- Deletes the requested thread's state DB row as the commit point, then
best-effort cleans associated state including spawned descendants,
goals, spawn edges, logs, dynamic tools, and agent job assignments.
- Updates app-server API docs and generated protocol schema/TypeScript
fixtures.
2026-06-10 11:22:12 -07:00
hefuc-oai 0177231ca0 feat(app-server): add remote control pairing status RPC (#26450)
## What

Exposes the pairing status transport as experimental app-server v2 RPC
`remoteControl/pairing/status`.

- Adds request/response protocol types for exactly one lookup key:
`pairingCode` or `manualPairingCode`, returning `{ claimed }`.
- Registers the RPC with `global_shared_read("remote-control-pairing")`.
- Wires the method through `MessageProcessor` and
`RemoteControlRequestProcessor`.
- Validates missing/conflicting pairing-code params as invalid requests.
- Documents the RPC in `app-server/README.md`.
- Adds processor, protocol export, and JSON-RPC integration coverage for
both code paths.

## Why

This is the app-server surface the desktop app can poll while the
QR/manual pairing modal is active.

Depends on https://github.com/openai/codex/pull/26449
Related backend change: https://github.com/openai/openai/pull/990244

## Verification

- `cargo test --manifest-path app-server-protocol/Cargo.toml
remote_control`
- `cargo test --manifest-path app-server/Cargo.toml remote_control`
- `cargo fmt --all --check`
- `git diff --check`
2026-06-05 10:33:56 -07:00
Anton Panasenko 98a62a62ce feat(app-server): add remote control client management RPCs (#25785)
## Why

Remote-control clients need to list and revoke controller-device grants
without enabling or enrolling the local relay. These are signed-in
account-management operations, so coupling them to websocket, pairing,
enrollment, or persisted relay state would prevent clients from managing
stale grants from the picker.

Related enhancement request: N/A. This adds the Codex app-server surface
for the planned upstream environment-scoped revoke endpoint.

## What Changed

- Added experimental app-server v2 RPCs:
  - `remoteControl/client/list`
  - `remoteControl/client/revoke`
- Added picker-oriented protocol types and standard generated schema
fixtures. The list response intentionally omits backend account id,
enrollment status, and location fields.
- Added `app-server-transport/src/transport/remote_control/clients.rs`
for environment-scoped GET and DELETE requests. It builds escaped URL
path segments, forwards optional pagination query fields, sends ChatGPT
auth plus `chatgpt-account-id`, converts RFC3339 `last_seen_at` values
to Unix seconds, accepts `204 No Content` revoke responses, and retries
once after a `401`.
- Extracted shared ChatGPT auth loading and recovery into
`app-server-transport/src/transport/remote_control/auth.rs` so
websocket, pairing, and client management use the same account-auth
boundary.
- Retained the configured remote-control base URL on
`RemoteControlHandle` and resolve management URLs lazily, preserving
deferred validation while relay startup is disabled.
- Registered list as `global_shared_read("remote-control-clients")` and
revoke as `global("remote-control-clients")`.

## Verification

- Added transport coverage proving list and revoke work while relay
state is disabled, IDs are escaped, picker-only fields are returned,
timestamps are converted, revoke accepts `204`, auth headers are
forwarded, `401` retries exactly once, `403` is not retried, and
malformed list payloads retain decode context.
- Added an app-server integration test proving both JSON-RPC methods
work before relay enablement and successful revoke returns `{}`.
- Regenerated and validated experimental and standard app-server schema
fixtures.
2026-06-02 17:01:02 -07:00
Anton Panasenko 0002316687 feat(remote-control): add pairing start (#25675)
## Why

Remote control enrollment authorizes a desktop server, but app-server v2
did not expose the follow-up pairing operation needed to mint a
short-lived controller pairing artifact from that enrolled server.
Clients need a narrow RPC that starts pairing without exposing the
backend `serverId` or conflating pairing with websocket connection
state.

Issue: N/A; internal remote-control pairing API change.

## What Changed

Added experimental app-server v2 `remoteControl/pairing/start` with
`manualCode` input and `pairingCode`, nullable `manualPairingCode`,
`environmentId`, and Unix-seconds `expiresAt` output. The method
serializes under its own `global("remote-control-pairing")` scope and is
documented in `app-server/README.md`.

Extended the remote-control transport with private `/server/pair`
request/response types and normalized `pair_url` handling. Pairing uses
the current enrolled server bearer, refreshes that bearer when needed,
keeps backend `server_id` private, validates returned `server_id` and
`environment_id` against the current enrollment, and preserves backend
status/header/body context for failures and malformed responses.

Wired the request through `RemoteControlRequestProcessor` and
`MessageProcessor`, mapping unavailable/disabled pairing to
`invalid_request` and backend failures to internal errors.

## Verification

- `just test -p codex-app-server-transport`
- `just test -p codex-app-server
remote_control_pairing_start_returns_pairing_artifacts`
2026-06-02 01:05:50 +00:00
Michael Bolin 6536841d89 fix: rename McpServer to TestAppServer (#25701)
This PR brought to you via VS Code rather than Codex...

- opened `codex-rs/app-server/tests/common/mcp_process.rs`
- put the cursor on `McpServer`
- hit `F2` and renamed the symbol to `TestAppServer`
- went to the file tree
- hit enter and renamed `mcp_process.rs` to `test_app_server.rs`
- ran **Save All Files** from the Command Palette
- ran `just fmt`

The End

(Admittedly, most of the local variables for `TestAppServer` are still
named `mcp`, though.)
2026-06-01 21:49:38 +00:00