Commit Graph
15885 Commits
Author SHA1 Message Date
Michael Bolin 4bc32cd051 Merge 9ebf0b1f23 into sapling-pr-archive-bolinfest 2026-05-17 08:41:48 -07:00
Michael Bolin 9ebf0b1f23 thread-store: store permission profiles 2026-05-17 08:41:33 -07:00
Michael Bolin 0a83353ca3 test: reduce core sandbox policy test setup (#23036)
## Why

`SandboxPolicy` is a legacy compatibility shape, but several core tests
still used it for ordinary turn setup even when the runtime path now
carries `PermissionProfile`. With the first cleanup PR merged, this
follow-up trims more core test scaffolding so remaining `SandboxPolicy`
matches are easier to classify as production compatibility,
legacy-boundary coverage, or explicit conversion tests.

## What Changed

- Updated apply-patch handler and runtime tests to pass
`PermissionProfile` directly.
- Changed sandboxing test helpers to build permission profiles without
first creating `SandboxPolicy` values.
- Converted request-permissions integration turns to pass
`PermissionProfile` through the test helper, leaving legacy sandbox
projection at the `Op::UserTurn` boundary.
- Converted unified exec integration helpers and direct turn submissions
to use `PermissionProfile` values instead of `SandboxPolicy` setup.
- Removed now-unused `SandboxPolicy` imports from the touched core
tests.

## Test Plan

- `just fmt`
- `cargo test -p codex-core --lib tools::sandboxing::tests`
- `cargo test -p codex-core --lib tools::runtimes::apply_patch::tests`
- `cargo test -p codex-core --lib tools::handlers::apply_patch::tests`
- `cargo test -p codex-core --lib unified_exec::process_manager::tests`
- `cargo test -p codex-core --test all request_permissions::`
- `cargo test -p codex-core --test all unified_exec::`
- `just fix -p codex-core`
2026-05-17 08:39:41 -07:00
jif-oai 545ede569c Make multi-agent v2 tool namespace configurable (#23147)
## Summary
- Add `features.multi_agent_v2.tool_namespace` with config/schema
validation for Responses-compatible namespace values.
- Thread the resolved namespace into `ToolsConfig` for normal turns and
review turns.
- Wrap MultiAgentV2 tool specs and registry names in the configured
namespace when namespace tools are supported, while falling back to the
plain tool names when they are not.

## Validation
- `just fmt`
- `just write-config-schema`
- `cargo test -p codex-features multi_agent_v2_feature_config --
--nocapture`
- `cargo test -p codex-core test_build_specs_multi_agent_v2 --
--nocapture`
- `cargo test -p codex-core multi_agent_v2_config -- --nocapture`
- `cargo test -p codex-core
multi_agent_v2_rejects_invalid_tool_namespace -- --nocapture`
- `cargo test -p codex-tools`
- `git diff --check`
2026-05-17 15:27:43 +02:00
Ahmed Ibrahim f0166cadbb [codex] Return TurnResult from Python turn handles (#23151)
## Why

`TurnHandle.run()` returned the raw app-server `Turn`, whose live
start/completed payloads do not include loaded `items`, so users saw
empty `items` after starting a turn. That made the handle-based path
behave differently from `Thread.run(...)`, and pushed examples toward
persisted-thread reads plus helper extraction.

This PR makes the run APIs standalone: starting a turn and running it
returns collected turn data directly, or fails visibly when required
stream events are missing.

## What Changed

- Replaces the public `RunResult` export with `TurnResult`.
- Adds turn metadata to `TurnResult`: `id`, `status`, `error`,
`started_at`, `completed_at`, and `duration_ms`, alongside
`final_response`, `items`, and `usage`.
- Changes `TurnHandle.run()` and `AsyncTurnHandle.run()` to consume
stream events with the same collector used by `Thread.run(...)`.
- Exports `TurnError` from `openai_codex.types` for the new result
shape.
- Updates tests, examples, docs, and the walkthrough notebook to use
`result.final_response` and `result.items` directly.
- Removes persisted-thread helper paths and placeholder/skipped control
flows from the public examples and notebook.

## Verification

- `python3 -m py_compile ...` over changed SDK, example, and test Python
files.
- `python3 -c "import json;
json.load(open('sdk/python/notebooks/sdk_walkthrough.ipynb'))"`
- `git diff --check`
- `PYTHONPATH=sdk/python/src python3 -c ...` import/signature smoke for
`TurnResult`, `TurnHandle.run`, and `AsyncTurnHandle.run`.
2026-05-17 06:17:22 -07:00
Ahmed Ibrahim 4c89772314 sdk/python: add first-class login support (#23093)
## Why

The Python SDK can already create threads and run turns, but
authentication still has to be arranged outside the SDK. App-server
already exposes account login, account inspection, logout, and
`account/login/completed` notifications, so SDK users currently have to
work around a missing public client layer for a core setup step.

This change makes authentication a normal SDK workflow while preserving
the backend flow shape: API-key login completes immediately, and
interactive ChatGPT flows return live handles that complete later
through app-server notifications.

## What changed

- Added public sync and async auth methods on `Codex` / `AsyncCodex`:
  - `login_api_key(...)`
  - `login_chatgpt()`
  - `login_chatgpt_device_code()`
  - `account(...)`
  - `logout()`
- Added public browser-login and device-code handle types with
attempt-local `wait()` and `cancel()` helpers. Cancellation stays on the
handle instead of a root-level SDK method.
- Extended the Python app-server client and notification router so login
completion events are routed by `login_id` without consuming unrelated
global notifications.
- Kept login request/handle logic in a focused internal `_login.py`
module so `api.py` remains the public facade instead of absorbing more
auth plumbing.
- Exported the new handle types plus curated account/login response
types from the SDK surfaces.
- Updated SDK docs, added sync/async login walkthrough examples, and
added a notebook login walkthrough cell.

## Verification

Added SDK coverage for:

- API-key login, account readback, and logout through the app-server
harness in both sync and async clients.
- Browser login cancellation plus `handle.wait()` completion through the
real app-server boundary used by the Python SDK harness.
- Waiter routing that stays scoped across replaced interactive login
attempts, plus async handle cancellation coverage.
- Login notification demuxing, replay of early completion events, and
async client delegation.
- Public export/signature assertions.
- Real integration-suite smoke coverage for the new examples and
notebook login cell.
2026-05-16 19:49:28 -07:00
Eric Traut 0445b290fe [1 of 4] tui: route primary settings writes through app server (#22913)
## Why
The TUI can run against a remote app server, but several high-traffic
settings still persisted by editing the local config file. That sends
remote sessions' preference writes to the wrong machine and lets local
disk state drift from the app-server-owned config.

This is **[1 of 4]** in a stacked series that moves TUI-owned config
mutations onto app-server APIs.

## What changed
- Added a small TUI helper for typed app-server config writes.
- Routed primary interactive preference writes through
`config/batchWrite`.
- Preserved existing profile scoping for settings that already support
`profiles.<profile>.*` overrides.

## Config keys affected
- `model`
- `model_reasoning_effort`
- `personality`
- `service_tier`
- `plan_mode_reasoning_effort`
- `approvals_reviewer`
- `notice.fast_default_opt_out`
- Profile-scoped equivalents under `profiles.<profile>.*`

## Suggested manual validation
- Connect the TUI to a remote app server, change `model` and
`model_reasoning_effort`, reconnect, and confirm the remote config
retained both values while the local `config.toml` did not change.
- Change `personality`, `plan_mode_reasoning_effort`, and the explicit
auto-review selection, then reconnect and confirm those choices persist
through the app server.
- Clear the service tier back to default and confirm `service_tier` is
cleared while `notice.fast_default_opt_out = true` is persisted
remotely.
- Repeat one setting change with an active profile and confirm the write
lands under `profiles.<profile>.*`.

## Stack
1. [#22913](https://github.com/openai/codex/pull/22913) `[1 of 4]`
primary settings writes
2. [#22914](https://github.com/openai/codex/pull/22914) `[2 of 4]` app
and skill enablement
3. [#22915](https://github.com/openai/codex/pull/22915) `[3 of 4]`
feature and memory toggles
4. [#22916](https://github.com/openai/codex/pull/22916) `[4 of 4]`
startup and onboarding bookkeeping
2026-05-16 14:27:02 -07:00
sayan-oai 061a614d85 multiagent: trim model-visible description, cap to 5 models (#23069)
## Why

The `spawn_agent` model override guidance is uncapped and bloating
context. We need to trim down each entry and cap total entries.

picked 5 as cap, we can change

## What changed

- Cap the model override summaries shown in `spawn_agent` to the first 5
picker-visible models, preserving the existing priority ordering from
the models manager.
- Condense each rendered entry to the actionable pieces the model needs:
  - use the model slug as the label
  - render compact reasoning effort lists with the default marked inline
- render only service tier IDs, and omit the clause when no tiers are
available
- Update coverage so the compact formatter shape and the top-5 cap are
exercised, and keep the end-to-end request assertion aligned with real
model metadata.

## Example

Before:

`- gpt-5.4 ('gpt-5.4\'): Strong model for everyday coding. Default
reasoning effort: medium. Supported reasoning efforts: low (Fast
responses with lighter reasoning), medium (Balances speed and reasoning
depth for everyday tasks), high (Greater reasoning depth for complex
problems), xhigh (Extra high reasoning depth for complex problems).
Supported service tiers: priority (Fast: 1.5x speed, increased usage).`

After:

`- 'gpt-5.4': Strong model for everyday coding. Reasoning efforts: low,
medium (default), high, xhigh. Service tiers: priority.`
2026-05-16 13:43:30 -07:00
Miaolin Min 6941f5c2c5 [codex] preserve MCP result meta in McpToolCallItemResult (#22946)
## Summary

https://openai.slack.com/archives/C0ARA9UAQEA/p1778890981647319?thread_ts=1778888537.934319&cid=C0ARA9UAQEA


- Add `_meta` to exec JSONL MCP tool call result events.
- Copy MCP result metadata through the JSONL event conversion.
- Add a focused test that verifies `_meta` is serialized as `_meta` and
not `meta`.


## Verification

https://www.notion.so/openai/Miaolin-0516-_meta-population-debug-3628e50b62b08074b365e0ce1ffb8f74
2026-05-16 13:27:44 -07:00
Michael Zeng b200dd1b6f exec-server: support auth-backed remote executor registration (#22769)
This updates remote `exec-server` registration to use normal Codex auth
instead of a registry-issued credential. The registry request is built
from the existing auth-provider path, which preserves the biscuit-only
registry contract introduced in
[openai/openai#924101](https://github.com/openai/openai/pull/924101)
while removing the old remote registry bearer env var and its direct
transport assumptions.

The default remote flow uses persisted ChatGPT auth from the normal
Codex config/storage path. This PR also includes the containerized Agent
Identity path needed by
[openai/openai#924260](https://github.com/openai/openai/pull/924260):
remote `exec-server` accepts `--allow-agent-identity-auth`, permits
Agent Identity auth loaded from `CODEX_ACCESS_TOKEN` only when that flag
is present, and reuses the existing Agent task registration plus derived
`AgentAssertion` header generation. API-key auth remains unsupported,
and Agent Identity stays opt-in.

Validation performed beyond normal presubmit coverage:
- `cargo fmt --all --check`
- `cargo check -p codex-cli`
- `cargo test -p codex-exec-server`
- `cargo test -p codex-cli exec_server_agent_identity_auth_flag_`
- `cargo test -p codex-cli remote_exec_server_auth_mode_`

I also attempted `cargo test -p codex-cli`. The new CLI tests passed
inside that run, but the suite ended on an unrelated local
marketplace-state failure in
`plugin_list_excludes_unconfigured_repo_local_marketplaces`.
2026-05-16 12:48:28 -07:00
Michael Bolin 9b94e173c0 Merge 0a3b7f74c6 into sapling-pr-archive-bolinfest 2026-05-16 12:19:51 -07:00
Michael Bolin 0a3b7f74c6 test: reduce core sandbox policy test setup 2026-05-16 12:19:38 -07:00
Michael Bolin 9838b4c5cb Merge 9e7f13ca34 into sapling-pr-archive-bolinfest 2026-05-16 12:13:08 -07:00
Michael Bolin 9e7f13ca34 test: reduce core sandbox policy test setup 2026-05-16 12:12:53 -07:00
Michael Bolin d91bc15618 test: construct permission profiles directly (#23030)
## Why

`SandboxPolicy` is now a legacy compatibility shape, but several tests
still built a `SandboxPolicy` only to immediately convert it into
`PermissionProfile` for APIs that already accept canonical runtime
permissions. Those detours make it harder to audit where legacy sandbox
policy is still required, because boundary-only usages are mixed
together with ordinary test setup.

## What Changed

- Updated tests in `codex-core`, `codex-exec`, `codex-analytics`, and
`codex-config` to construct `PermissionProfile` values directly when the
code under test takes a permission profile.
- Changed exec-policy, request-permissions, session, and sandbox test
helpers to pass `PermissionProfile` through instead of converting from
`SandboxPolicy` internally.
- Left `SandboxPolicy` in place where tests are explicitly exercising
legacy compatibility or request/response boundaries.

## Test Plan

- `cargo test -p codex-analytics -p codex-config`
- `cargo test -p codex-core --lib safety::tests`
- `cargo test -p codex-core --lib exec_policy::tests::`
- `cargo test -p codex-core --lib exec::tests`
- `cargo test -p codex-core --lib guardian_review_session_config`
- `cargo test -p codex-core --lib tools::network_approval::tests`
- `cargo test -p codex-core --lib
tools::runtimes::shell::unix_escalation::tests`
- `cargo test -p codex-core --lib managed_network`
- `cargo test -p codex-core --test all request_permissions::`
- `cargo test -p codex-exec sandbox`


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23030).
* #23036
* __->__ #23030
2026-05-16 12:12:37 -07:00
Eric Traut 941e7f825e Improve goal completion usage reporting (#22907)
## Why

Goal completion follow-up turns currently receive a preformatted English
usage sentence such as `time used: 2586 seconds`. That nudges the model
to echo an awkward raw seconds count in the final reply, even though the
tool result already exposes structured usage fields like
`goal.timeUsedSeconds`, `goal.tokensUsed`, and `goal.tokenBudget`.

## What changed

- Replace the preformatted completion usage sentence with guidance to
read the structured goal fields from the tool result.
- Preserve token-budget reporting while allowing the model to phrase
elapsed time in a concise, human-friendly way that fits the response
language.
- Update core coverage for both the generated completion guidance and
the session flow that forwards it back to the model.

## Verification

Previously, it would have output a final message indicating that it
"worked for 303 seconds". Now it shows the following:

<img width="286" height="35" alt="image"
src="https://github.com/user-attachments/assets/d7011880-9449-46a7-856f-4e50ae00eb45"
/>
2026-05-16 11:49:40 -07:00
Ahmed Ibrahim a280248021 [codex] Split Python SDK helper logic (#22939)
## Summary
- Move approval-mode mapping into
`sdk/python/src/openai_codex/_approval_mode.py`.
- Move initialize metadata parsing and normalization into
`sdk/python/src/openai_codex/_initialize_metadata.py`.
- Keep the public `ApprovalMode` export stable and retarget direct
metadata helper coverage.

## Integration coverage
- Add an app-server harness smoke that exercises sync and async SDK
initialization plus thread creation.

## Validation
- Local tests were not run per repo guidance. CI should validate this
branch once the PR is online.
2026-05-16 09:47:51 -07:00
Michael Bolin a307620b5d merge commit for archive created by Sapling 2026-05-16 08:55:44 -07:00
Michael Bolin 7779e7f1f7 test: reduce core sandbox policy test setup 2026-05-16 08:55:30 -07:00
Michael Bolin 44f167ffa8 test: construct permission profiles directly 2026-05-16 08:55:30 -07:00
Michael Bolin a855113712 Merge 8dcdebc675 into sapling-pr-archive-bolinfest 2026-05-16 08:07:57 -07:00
Michael Bolin e793e531b3 Merge 220d415ede into sapling-pr-archive-bolinfest 2026-05-16 08:05:18 -07:00
Michael Bolin 8dcdebc675 test: reduce core sandbox policy test setup 2026-05-16 08:05:08 -07:00
Michael Bolin 220d415ede test: construct permission profiles directly 2026-05-16 08:05:08 -07:00
Michael Bolin 2c611aba2f Merge 6ace6c2827 into sapling-pr-archive-bolinfest 2026-05-16 07:51:31 -07:00
Michael Bolin 6ace6c2827 test: construct permission profiles directly 2026-05-16 07:51:16 -07:00
Michael Bolin e5e148b087 Merge 12a3e8cd25 into sapling-pr-archive-bolinfest 2026-05-16 07:46:07 -07:00
Michael Bolin 12a3e8cd25 test: construct permission profiles directly 2026-05-16 07:45:52 -07:00
Michael Bolin 8f033b4abe merge commit for archive created by Sapling 2026-05-16 07:34:55 -07:00
Michael Bolin 8bd521e0bf test: construct permission profiles directly 2026-05-16 07:34:47 -07:00
Michael Bolin 6e2cd91fa6 merge commit for archive created by Sapling 2026-05-16 07:28:36 -07:00
Michael Bolin 7003cff49e test: construct permission profiles directly 2026-05-16 07:28:16 -07:00
Michael Bolin 108234b5eb core: set permission profiles from snapshots (#22920)
## Why

#22891 moved the TUI turn-command path to pass `ActivePermissionProfile`
instead of the full `PermissionProfile`, but the remaining
config/session bridge still accepted the concrete `PermissionProfile`
and active profile id as separate arguments. That shape made it too easy
for future callers to update the concrete profile and active profile id
out of sync.

This PR makes the trusted session snapshot path pass one coherent value
into `Permissions`, while keeping `requirements.toml` enforcement owned
by the existing constrained permission state.

## What Changed

- Added `PermissionProfileSnapshot` as the public snapshot value for
trusted session/config synchronization.
- Changed `Permissions::set_permission_profile_from_session_snapshot()`
and `replace_permission_profile_from_session_snapshot()` to take a
`PermissionProfileSnapshot`.
- Updated the replacement path to derive its constrained
`PermissionProfile` from the snapshot, so callers cannot pass a separate
profile that disagrees with the snapshot.
- Removed the internal tuple-style
`PermissionProfileState::set_active_permission_profile()` mutation path.
- Updated core session projection and TUI call sites to construct
explicit legacy or active snapshots.
- Documented the snapshot constructors so legacy use and id/profile
mismatch hazards are called out at the API boundary.
- Added a focused config test that verifies snapshot updates still
respect existing permission constraints.

## How To Review

1. Start with `codex-rs/core/src/config/resolved_permission_profile.rs`;
`PermissionProfileSnapshot` is the public wrapper, while
`ResolvedPermissionProfile` stays internal.
2. Check `codex-rs/core/src/config/mod.rs` to confirm both
session-snapshot setters validate through `PermissionProfileState` and
no longer accept loose profile/id pairs.
3. Skim `codex-rs/core/src/session/session.rs` for the session
projection path; it now builds the snapshot before installing it.
4. Skim the TUI changes as call-site migration from loose argument pairs
to explicit snapshot construction.

## Verification

- `cargo test -p codex-core
permission_snapshot_setter_preserves_permission_constraints`
- `cargo test -p codex-tui status_permissions_`
- `cargo test -p codex-tui
session_configured_preserves_profile_workspace_roots`
- `just fix -p codex-core -p codex-tui`
2026-05-16 07:26:18 -07:00
Eric Traut de9c5c0226 Fix Windows doctor npm root probe (#22967)
## Why
On Windows npm-managed installs expose the working shim as `npm.cmd`.
`codex doctor` probed bare `npm`, which could incorrectly report that
npm global-root inspection was unavailable even when the install was
healthy.

Fixes #22964.

## What changed
- Use `npm.cmd` for the doctor npm-root probe on Windows.
- Keep the existing `npm` probe on non-Windows platforms.
2026-05-16 00:39:27 -07:00
Ahmed Ibrahim 326e31ab65 [codex] Refine Python SDK user-facing docs (#22941)
## Summary
- Remove maintainer and release-process wording from the Python SDK
README and docs.
- Rewrite SDK-facing comments/docstrings so they read as standalone
product documentation.
- Add a real app-server integration smoke that follows the public
quickstart-style `Codex() -> thread_start() -> run()` path.

## Integration coverage
- Add `test_real_quickstart_style_flow_smoke` in the real app-server
integration suite.

## Validation
- Local tests were not run per repo guidance. CI should validate this
branch once the PR is online.
2026-05-15 19:55:05 -07:00
Michael Bolin b12d16f952 merge commit for archive created by Sapling 2026-05-15 17:38:25 -07:00
Michael Bolin 49a9062253 windows-sandbox: drive write roots from resolved permissions 2026-05-15 17:38:07 -07:00
Michael Bolin f8724cf510 merge commit for archive created by Sapling 2026-05-15 17:33:32 -07:00
Michael Bolin 3d98e859e5 core: set permission profiles from snapshots 2026-05-15 17:31:52 -07:00
Michael Bolin 5bf17a4827 Merge c42e3703b3 into sapling-pr-archive-bolinfest 2026-05-15 17:21:09 -07:00
Michael Bolin c42e3703b3 windows-sandbox: drive write roots from resolved permissions 2026-05-15 17:21:02 -07:00
Michael Bolin 9025550709 app-server-protocol: remove PermissionProfile from API (#22924)
## Why

The app server API should expose permission profile identity, not the
lower-level runtime permission model. `PermissionProfile` is the
compiled sandbox/network representation that the server uses internally;
exposing it through app-server-protocol forces clients to understand
details that should remain implementation-level.

The API boundary should prefer `ActivePermissionProfile`: a stable
profile id, plus future parent-profile metadata, that clients can pass
back when they want to select the same active permissions. This also
avoids schema generation collisions between the app-server v2 API type
space and the core protocol model.

Incidentally, while PR makes a number of changes to `command/exec`, note
that we are hoping to deprecate this API in favor of `process/spawn`, so
we don't need to be too finicky about these changes.

## What Changed

- Removed `PermissionProfile` from the app-server-protocol API surface,
including generated schema and TypeScript exports.
- Changed `CommandExecParams.permissionProfile` to
`ActivePermissionProfile`.
- Resolve command exec profile ids through `ConfigManager` for the
command cwd, matching turn override selection semantics.
- Updated downstream TUI tests/helpers to use core permission types
directly instead of app-server-protocol `PermissionProfile` shims.
2026-05-15 17:10:15 -07:00
Michael Bolin f11f3e4ef8 merge commit for archive created by Sapling 2026-05-15 17:03:29 -07:00
Michael Bolin de5a796e9a windows-sandbox: drive write roots from resolved permissions 2026-05-15 17:03:11 -07:00
Michael Bolin b90513496b merge commit for archive created by Sapling 2026-05-15 16:54:07 -07:00
Michael Bolin 70a7dcacd4 app-server-protocol: use active permission profile for command exec 2026-05-15 16:53:59 -07:00
Michael Bolin 89a88a9982 merge commit for archive created by Sapling 2026-05-15 16:43:44 -07:00
Michael Bolin 07b7e3c426 app-server-protocol: use active permission profile for command exec 2026-05-15 16:43:35 -07:00
Michael Bolin 62fb720137 merge commit for archive created by Sapling 2026-05-15 16:39:11 -07:00
Michael Bolin 78674c0f52 app-server-protocol: use active permission profile for command exec 2026-05-15 16:39:02 -07:00