Commit Graph
10741 Commits
Author SHA1 Message Date
Michael Bolin aefa684b80 merge commit for archive created by Sapling 2026-03-31 14:04:01 -07:00
Michael Bolin 5565515429 ci: verify Bazel clippy lints stay synced with Cargo workspace 2026-03-31 14:03:42 -07:00
Michael Bolin b977dc96dc ci: verify codex-rs Cargo manifests inherit workspace settings 2026-03-31 14:03:42 -07:00
Michael Bolin 2f85a4c5fa merge commit for archive created by Sapling 2026-03-31 12:32:55 -07:00
Michael Bolin 4c319c117a ci: verify Bazel clippy lints stay synced with Cargo workspace 2026-03-31 12:32:38 -07:00
Michael Bolin 4d1c91f417 ci: verify codex-rs Cargo manifests inherit workspace settings 2026-03-31 12:32:38 -07:00
Michael Bolin d53d2db436 Merge e94a91e8ea into sapling-pr-archive-bolinfest 2026-03-31 09:59:44 -07:00
Michael Bolin e94a91e8ea ci: verify Bazel clippy lints stay synced with Cargo workspace 2026-03-31 09:59:34 -07:00
Michael Bolin c26c1c071d merge commit for archive created by Sapling 2026-03-31 09:57:42 -07:00
Michael Bolin 20ab10d982 ci: verify codex-rs Cargo manifests inherit workspace settings 2026-03-31 09:57:24 -07:00
Michael Bolin ce11bd4353 Merge fdb5c20763 into sapling-pr-archive-bolinfest 2026-03-31 09:30:57 -07:00
Michael Bolin fdb5c20763 ci: verify Bazel clippy lints stay synced with Cargo workspace 2026-03-31 09:30:47 -07:00
Michael Bolin 03b2465591 fix: fix clippy issue caught by cargo but not bazel (#16345)
I noticed that
https://github.com/openai/codex/actions/workflows/rust-ci-full.yml
started failing on my own PR,
https://github.com/openai/codex/pull/16288, even though CI was green
when I merged it.

Apparently, it introduced a lint violation that was [correctly!] caught
by our Cargo-based clippy runner, but not our Bazel-based one.

My next step is to figure out the reason for the delta between the two
setups, but I wanted to get us green again quickly, first.
2026-03-31 16:01:06 +00:00
Michael Bolin 8d0d89eda1 merge commit for archive created by Sapling 2026-03-31 08:44:44 -07:00
Michael Bolin 24010d8d90 fix: fix clippy issue caught by cargo but not bazel 2026-03-31 08:44:31 -07:00
jif-oai b09b58ce2d chore: drop interrupt from send_message (#16324) 2026-03-31 16:02:45 +02:00
jif-oai 285f4ea817 feat: restrict spawn_agent v2 to messages (#16325) 2026-03-31 14:52:55 +02:00
jif-oai 4c72e62d0b fix: update fork boundaries computation (#16322) 2026-03-31 14:10:43 +02:00
jif-oaiandCodex 1fc8aa0e16 feat: fork pattern v2 (#15771)
Adds this:
```
properties.insert(
            "fork_turns".to_string(),
            JsonSchema::String {
                description: Some(
                    "Optional MultiAgentV2 fork mode. Use `none`, `all`, or a positive integer string such as `3` to fork only the most recent turns."
                        .to_string(),
                ),
            },
        );
        ```

---------

Co-authored-by: Codex <noreply@openai.com>
2026-03-31 13:06:08 +02:00
jif-oai 2b8d29ac0d nit: update aborted line (#16318) 2026-03-31 13:06:00 +02:00
jif-oai ec21e1fd01 chore: clean wait v2 (#16317) 2026-03-31 12:18:10 +02:00
jif-oai 25fbd7e40e fix: ma2 (#16238) 2026-03-31 11:22:38 +02:00
jif-oai 873e466549 fix: one shot end of turn (#16308)
Fix the death of the end of turn watcher
2026-03-31 11:11:33 +02:00
Michael Bolin 20f43c1e05 core: support dynamic auth tokens for model providers (#16288)
## Summary

Fixes #15189.

Custom model providers that set `requires_openai_auth = false` could
only use static credentials via `env_key` or
`experimental_bearer_token`. That is not enough for providers that mint
short-lived bearer tokens, because Codex had no way to run a command to
obtain a bearer token, cache it briefly in memory, and retry with a
refreshed token after a `401`.

This PR adds that provider config and wires it through the existing auth
design: request paths still go through `AuthManager.auth()` and
`UnauthorizedRecovery`, with `core` only choosing when to use a
provider-backed bearer-only `AuthManager`.

## Scope

To keep this PR reviewable, `/models` only uses provider auth for the
initial request in this change. It does **not** add a dedicated `401`
retry path for `/models`; that can be follow-up work if we still need it
after landing the main provider-token support.

## Example Usage

```toml
model_provider = "corp-openai"

[model_providers.corp-openai]
name = "Corp OpenAI"
base_url = "https://gateway.example.com/openai"
requires_openai_auth = false

[model_providers.corp-openai.auth]
command = "gcloud"
args = ["auth", "print-access-token"]
timeout_ms = 5000
refresh_interval_ms = 300000
```

The command contract is intentionally small:

- write the bearer token to `stdout`
- exit `0`
- any leading or trailing whitespace is trimmed before the token is used

## What Changed

- add `model_providers.<id>.auth` to the config model and generated
schema
- validate that command-backed provider auth is mutually exclusive with
`env_key`, `experimental_bearer_token`, and `requires_openai_auth`
- build a bearer-only `AuthManager` for `ModelClient` and
`ModelsManager` when a provider configures `auth`
- let normal Responses requests and realtime websocket connects use the
provider-backed bearer source through the same `AuthManager.auth()` path
- allow `/models` online refresh for command-auth providers and attach
the provider token to the initial `/models` request
- keep `auth.cwd` available as an advanced escape hatch and include it
in the generated config schema

## Testing

- `cargo test -p codex-core provider_auth_command`
- `cargo test -p codex-core
refresh_available_models_uses_provider_auth_token`
- `cargo test -p codex-core
test_deserialize_provider_auth_config_defaults`

## Docs

- `developers.openai.com/codex` should document the new
`[model_providers.<id>.auth]` block and the token-command contract
2026-03-31 01:37:27 -07:00
Michael Bolin 03ef58afe7 Merge 6ad436de9b into sapling-pr-archive-bolinfest 2026-03-31 01:26:39 -07:00
Michael Bolin 6ad436de9b core: support dynamic auth tokens for model providers 2026-03-31 01:26:22 -07:00
Michael Bolin 0071968829 auth: let AuthManager own external bearer auth (#16287)
## Summary

`AuthManager` and `UnauthorizedRecovery` already own token resolution
and staged `401` recovery. The missing piece for provider auth was a
bearer-only mode that still fit that design, instead of pushing a second
auth abstraction into `codex-core`.

This PR keeps the design centered on `AuthManager`: it teaches
`codex-login` how to own external bearer auth directly so later provider
work can keep calling `AuthManager.auth()` and `UnauthorizedRecovery`.

## Motivation

This is the middle layer for #15189.

The intended design is still:

- `AuthManager` encapsulates token storage and refresh
- `UnauthorizedRecovery` powers staged `401` recovery
- all request tokens go through `AuthManager.auth()`

This PR makes that possible for provider-backed bearer tokens by adding
a bearer-only auth mode inside `AuthManager` instead of building
parallel request-auth plumbing in `core`.

## What Changed

- move `ModelProviderAuthInfo` into `codex-protocol` so `core` and
`login` share one config shape
- add `login/src/auth/external_bearer.rs`, which runs the configured
command, caches the bearer token in memory, and refreshes it after `401`
- add `AuthManager::external_bearer_only(...)` for provider-scoped
request paths that should use command-backed bearer auth without
mutating the shared OpenAI auth manager
- add `AuthManager::shared_with_external_chatgpt_auth_refresher(...)`
and rename the other `AuthManager` helpers that only apply to external
ChatGPT auth so the ChatGPT-only path is explicit at the call site
- keep external ChatGPT refresh behavior unchanged while ensuring
bearer-only external auth never persists to `auth.json`

## Testing

- `cargo test -p codex-login`
- `cargo test -p codex-protocol`





---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16287).
* #16288
* __->__ #16287
2026-03-31 01:26:17 -07:00
Michael Bolin 947aa6f202 merge commit for archive created by Sapling 2026-03-31 01:19:11 -07:00
Michael Bolin e13e00c18a core: support dynamic auth tokens for model providers 2026-03-31 01:19:05 -07:00
Michael Bolin 1a1434d155 merge commit for archive created by Sapling 2026-03-31 01:12:36 -07:00
Michael Bolin 2bb3ea6f90 core: support dynamic auth tokens for model providers 2026-03-31 01:12:09 -07:00
Michael Bolin 7fb376dafc Merge ea9c6ab752 into sapling-pr-archive-bolinfest 2026-03-31 01:03:35 -07:00
Michael Bolin 6afaa7d62b auth: let AuthManager own external bearer auth 2026-03-31 01:03:24 -07:00
Michael Bolin ea9c6ab752 core: support dynamic auth tokens for model providers 2026-03-31 01:03:24 -07:00
Michael Bolin ea650a91b3 auth: generalize external auth tokens for bearer-only sources (#16286)
## Summary

`ExternalAuthRefresher` was still shaped around external ChatGPT auth:
`ExternalAuthTokens` always implied ChatGPT account metadata even when a
caller only needed a bearer token.

This PR generalizes that contract so bearer-only sources are
first-class, while keeping the existing ChatGPT paths strict anywhere we
persist or rebuild ChatGPT auth state.

## Motivation

This is the first step toward #15189.

The follow-on provider-auth work needs one shared external-auth contract
that can do both of these things:

- resolve the current bearer token before a request is sent
- return a refreshed bearer token after a `401`

That should not require a second token result type just because there is
no ChatGPT account metadata attached.

## What Changed

- change `ExternalAuthTokens` to carry `access_token` plus optional
`ExternalAuthChatgptMetadata`
- add helper constructors for bearer-only tokens and ChatGPT-backed
tokens
- add `ExternalAuthRefresher::resolve()` with a default no-op
implementation so refreshers can optionally provide the current token
before a request is sent
- keep ChatGPT-only persistence strict by continuing to require ChatGPT
metadata anywhere the login layer seeds or reloads ChatGPT auth state
- update the app-server bridge to construct the new token shape for
external ChatGPT auth refreshes

## Testing

- `cargo test -p codex-login`


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16286).
* #16288
* #16287
* __->__ #16286
2026-03-31 01:02:46 -07:00
Michael Bolin 06b566fca3 merge commit for archive created by Sapling 2026-03-31 01:01:03 -07:00
Michael Bolin 0b30a7a940 core: support dynamic auth tokens for model providers 2026-03-31 00:59:45 -07:00
Michael Bolin 4a42882bba auth: let AuthManager own external bearer auth 2026-03-31 00:59:42 -07:00
Michael Bolin 59ba8c8995 merge commit for archive created by Sapling 2026-03-31 00:34:48 -07:00
Michael Bolin f042fd7f74 core: support dynamic auth tokens for model providers 2026-03-31 00:34:36 -07:00
Michael Bolin 346440cb7b auth: let AuthManager own external bearer auth 2026-03-31 00:34:30 -07:00
Michael Bolin 86e6098af8 merge commit for archive created by Sapling 2026-03-30 22:52:15 -07:00
Michael Bolin e93aaed334 core: support dynamic auth tokens for model providers 2026-03-30 22:51:43 -07:00
Michael Bolin 5e3780a304 auth: let AuthManager own external bearer auth 2026-03-30 22:51:26 -07:00
Michael Bolin 32e8fa82ff merge commit for archive created by Sapling 2026-03-30 21:52:07 -07:00
Michael Bolin 56f793e8ec core: support dynamic auth tokens for model providers 2026-03-30 21:51:54 -07:00
Michael Bolin 4dd489f6bb auth: let AuthManager own external bearer auth 2026-03-30 21:51:54 -07:00
Michael Bolin 11bdc7eff3 merge commit for archive created by Sapling 2026-03-30 17:35:57 -07:00
Michael Bolin 218221b9f2 core: support dynamic auth tokens for model providers 2026-03-30 17:35:48 -07:00
Michael Bolin 1ec469265f merge commit for archive created by Sapling 2026-03-30 17:33:27 -07:00