Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- codex-rs/.cargo/audit.toml +15 -0
- codex-rs/.cargo/config.toml +11 -0
- codex-rs/agent-graph-store/BUILD.bazel +6 -0
- codex-rs/agent-graph-store/Cargo.toml +26 -0
- codex-rs/agent-roles/BUILD.bazel +6 -0
- codex-rs/agent-roles/Cargo.toml +23 -0
- codex-rs/analytics/BUILD.bazel +6 -0
- codex-rs/analytics/Cargo.toml +35 -0
- codex-rs/app-server-client/BUILD.bazel +6 -0
- codex-rs/app-server-client/Cargo.toml +40 -0
- codex-rs/app-server-client/README.md +66 -0
- codex-rs/app-server-daemon/BUILD.bazel +6 -0
- codex-rs/app-server-daemon/Cargo.toml +46 -0
- codex-rs/app-server-daemon/README.md +192 -0
- codex-rs/app-server-protocol-noop-macros/BUILD.bazel +7 -0
- codex-rs/app-server-protocol-noop-macros/Cargo.toml +13 -0
- codex-rs/app-server-protocol/BUILD.bazel +19 -0
- codex-rs/app-server-protocol/Cargo.toml +56 -0
- codex-rs/app-server-test-client/BUILD.bazel +6 -0
- codex-rs/app-server-test-client/Cargo.toml +31 -0
- codex-rs/app-server-test-client/README.md +184 -0
- codex-rs/app-server/BUILD.bazel +31 -0
- codex-rs/app-server/Cargo.toml +155 -0
- codex-rs/app-server/README.md +285 -0
- codex-rs/apply-patch/BUILD.bazel +6 -0
- codex-rs/apply-patch/Cargo.toml +35 -0
- codex-rs/arg0/BUILD.bazel +6 -0
- codex-rs/arg0/Cargo.toml +35 -0
- codex-rs/async-utils/BUILD.bazel +6 -0
- codex-rs/async-utils/Cargo.toml +18 -0
- codex-rs/attachment-store/BUILD.bazel +6 -0
- codex-rs/attachment-store/Cargo.toml +20 -0
- codex-rs/aws-auth/BUILD.bazel +6 -0
- codex-rs/aws-auth/Cargo.toml +26 -0
- codex-rs/backend-client/BUILD.bazel +7 -0
- codex-rs/backend-client/Cargo.toml +31 -0
- codex-rs/build-info/BUILD.bazel +6 -0
- codex-rs/build-info/Cargo.toml +24 -0
- codex-rs/build-info/build.rs +8 -0
- codex-rs/chatgpt/BUILD.bazel +6 -0
- codex-rs/chatgpt/Cargo.toml +31 -0
- codex-rs/chatgpt/README.md +5 -0
- codex-rs/cli/BUILD.bazel +23 -0
- codex-rs/cli/Cargo.toml +138 -0
- codex-rs/cli/build.rs +5 -0
- codex-rs/cloud-tasks-client/BUILD.bazel +6 -0
- codex-rs/cloud-tasks-client/Cargo.toml +25 -0
- codex-rs/cloud-tasks-mock-client/BUILD.bazel +6 -0
- codex-rs/cloud-tasks-mock-client/Cargo.toml +20 -0
- codex-rs/cloud-tasks/BUILD.bazel +7 -0
codex-rs/.cargo/audit.toml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[advisories]
|
| 2 |
+
# Reviewed 2026-07-02. Keep this list in sync with ../deny.toml.
|
| 3 |
+
ignore = [
|
| 4 |
+
"RUSTSEC-2024-0388", # derivative 2.2.0 via starlark/starlark_syntax; upstream crate is unmaintained
|
| 5 |
+
"RUSTSEC-2025-0057", # fxhash 0.2.1 via starlark_map/bm25; upstream crate is unmaintained
|
| 6 |
+
"RUSTSEC-2024-0436", # paste 1.0.15 via starlark/v8; upstream crate is unmaintained
|
| 7 |
+
"RUSTSEC-2023-0089", # atomic-polyfill via postcard/heapless/pagable; upstream crate is unmaintained
|
| 8 |
+
"RUSTSEC-2024-0320", # yaml-rust via syntect; remove when syntect drops or updates it
|
| 9 |
+
"RUSTSEC-2025-0141", # bincode via syntect; remove when syntect drops or updates it
|
| 10 |
+
"RUSTSEC-2026-0118", # hickory-proto via rama-dns/rama-tcp; remove when rama updates to hickory 0.26.1 or hickory-net
|
| 11 |
+
"RUSTSEC-2026-0119", # hickory-proto via rama-dns/rama-tcp; remove when rama updates to hickory 0.26.1 or hickory-net
|
| 12 |
+
"RUSTSEC-2026-0173", # proc-macro-error2 via i18n-embed-fl/age/codex-secrets; remove when local secrets storage migrates off age or age drops i18n-embed-fl
|
| 13 |
+
"RUSTSEC-2026-0194", # quick-xml via plist/syntect and wayland-scanner; trusted inputs only; remove when rust-plist#191 and wayland-rs#938 are released
|
| 14 |
+
"RUSTSEC-2026-0195", # quick-xml via plist/syntect and wayland-scanner; trusted inputs only; remove when rust-plist#191 and wayland-rs#938 are released
|
| 15 |
+
]
|
codex-rs/.cargo/config.toml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[target.'cfg(all(windows, target_env = "msvc"))']
|
| 2 |
+
rustflags = ["-C", "link-arg=/STACK:8388608", "-C", "target-feature=+crt-static"]
|
| 3 |
+
|
| 4 |
+
# MSVC emits a warning about code that may trip "Cortex-A53 MPCore processor bug #843419" (see
|
| 5 |
+
# https://developer.arm.com/documentation/epm048406/latest) which is sometimes emitted by LLVM.
|
| 6 |
+
# Since Arm64 Windows 10+ isn't supported on that processor, it's safe to disable the warning.
|
| 7 |
+
[target.aarch64-pc-windows-msvc]
|
| 8 |
+
rustflags = ["-C", "link-arg=/STACK:8388608", "-C", "link-arg=/arm64hazardfree"]
|
| 9 |
+
|
| 10 |
+
[target.'cfg(all(windows, target_env = "gnu"))']
|
| 11 |
+
rustflags = ["-C", "link-arg=-Wl,--stack,8388608"]
|
codex-rs/agent-graph-store/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "agent-graph-store",
|
| 5 |
+
crate_name = "codex_agent_graph_store",
|
| 6 |
+
)
|
codex-rs/agent-graph-store/Cargo.toml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-agent-graph-store"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_agent_graph_store"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
codex-protocol = { workspace = true }
|
| 17 |
+
codex-state = { workspace = true }
|
| 18 |
+
serde = { workspace = true, features = ["derive"] }
|
| 19 |
+
thiserror = { workspace = true }
|
| 20 |
+
|
| 21 |
+
[dev-dependencies]
|
| 22 |
+
codex-utils-absolute-path = { workspace = true }
|
| 23 |
+
pretty_assertions = { workspace = true }
|
| 24 |
+
serde_json = { workspace = true }
|
| 25 |
+
tempfile = { workspace = true }
|
| 26 |
+
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync"] }
|
codex-rs/agent-roles/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "agent-roles",
|
| 5 |
+
crate_name = "codex_agent_roles",
|
| 6 |
+
)
|
codex-rs/agent-roles/Cargo.toml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-agent-roles"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
doctest = false
|
| 9 |
+
name = "codex_agent_roles"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
test = false
|
| 12 |
+
|
| 13 |
+
[lints]
|
| 14 |
+
workspace = true
|
| 15 |
+
|
| 16 |
+
[dependencies]
|
| 17 |
+
codex-config = { workspace = true }
|
| 18 |
+
codex-file-system = { workspace = true }
|
| 19 |
+
codex-utils-absolute-path = { workspace = true }
|
| 20 |
+
codex-utils-path-uri = { workspace = true }
|
| 21 |
+
serde = { workspace = true, features = ["derive"] }
|
| 22 |
+
toml = { workspace = true, features = ["preserve_order"] }
|
| 23 |
+
tracing = { workspace = true }
|
codex-rs/analytics/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "analytics",
|
| 5 |
+
crate_name = "codex_analytics",
|
| 6 |
+
)
|
codex-rs/analytics/Cargo.toml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-analytics"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
doctest = false
|
| 9 |
+
name = "codex_analytics"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
codex-app-server-protocol = { workspace = true }
|
| 17 |
+
codex-git-utils = { workspace = true }
|
| 18 |
+
codex-login = { workspace = true }
|
| 19 |
+
codex-model-provider = { workspace = true }
|
| 20 |
+
codex-plugin = { workspace = true }
|
| 21 |
+
codex-protocol = { workspace = true }
|
| 22 |
+
codex-state = { workspace = true }
|
| 23 |
+
os_info = { workspace = true }
|
| 24 |
+
serde = { workspace = true, features = ["derive"] }
|
| 25 |
+
serde_json = { workspace = true }
|
| 26 |
+
sha1 = { workspace = true }
|
| 27 |
+
tokio = { workspace = true, features = [
|
| 28 |
+
"macros",
|
| 29 |
+
"rt-multi-thread",
|
| 30 |
+
] }
|
| 31 |
+
tracing = { workspace = true, features = ["log"] }
|
| 32 |
+
|
| 33 |
+
[dev-dependencies]
|
| 34 |
+
codex-utils-absolute-path = { workspace = true }
|
| 35 |
+
pretty_assertions = { workspace = true }
|
codex-rs/app-server-client/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server-client",
|
| 5 |
+
crate_name = "codex_app_server_client",
|
| 6 |
+
)
|
codex-rs/app-server-client/Cargo.toml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server-client"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_app_server_client"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
codex-app-server = { workspace = true }
|
| 17 |
+
codex-app-server-protocol = { workspace = true }
|
| 18 |
+
codex-arg0 = { workspace = true }
|
| 19 |
+
codex-config = { workspace = true }
|
| 20 |
+
codex-core = { workspace = true }
|
| 21 |
+
codex-exec-server = { workspace = true }
|
| 22 |
+
codex-feedback = { workspace = true }
|
| 23 |
+
codex-protocol = { workspace = true }
|
| 24 |
+
codex-uds = { workspace = true }
|
| 25 |
+
codex-utils-absolute-path = { workspace = true }
|
| 26 |
+
codex-utils-rustls-provider = { workspace = true }
|
| 27 |
+
futures = { workspace = true }
|
| 28 |
+
serde = { workspace = true }
|
| 29 |
+
serde_json = { workspace = true }
|
| 30 |
+
tokio = { workspace = true, features = ["sync", "time", "rt"] }
|
| 31 |
+
tokio-tungstenite = { workspace = true }
|
| 32 |
+
toml = { workspace = true }
|
| 33 |
+
tracing = { workspace = true }
|
| 34 |
+
url = { workspace = true }
|
| 35 |
+
|
| 36 |
+
[dev-dependencies]
|
| 37 |
+
pretty_assertions = { workspace = true }
|
| 38 |
+
serde_json = { workspace = true }
|
| 39 |
+
tempfile = { workspace = true }
|
| 40 |
+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
codex-rs/app-server-client/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# codex-app-server-client
|
| 2 |
+
|
| 3 |
+
Shared in-process app-server client used by conversational CLI surfaces:
|
| 4 |
+
|
| 5 |
+
- `codex-exec`
|
| 6 |
+
- `codex-tui`
|
| 7 |
+
|
| 8 |
+
## Purpose
|
| 9 |
+
|
| 10 |
+
This crate centralizes startup and lifecycle management for an in-process
|
| 11 |
+
`codex-app-server` runtime, so CLI clients do not need to duplicate:
|
| 12 |
+
|
| 13 |
+
- app-server bootstrap and initialize handshake
|
| 14 |
+
- in-memory request/event transport wiring
|
| 15 |
+
- lifecycle orchestration around caller-provided startup identity
|
| 16 |
+
- graceful shutdown behavior
|
| 17 |
+
|
| 18 |
+
## Startup identity
|
| 19 |
+
|
| 20 |
+
Callers pass both the app-server `SessionSource` and the initialize
|
| 21 |
+
`client_info.name` explicitly when starting the facade.
|
| 22 |
+
|
| 23 |
+
That keeps thread metadata (for example in `thread/list` and `thread/read`)
|
| 24 |
+
aligned with the originating runtime without baking TUI/exec-specific policy
|
| 25 |
+
into the shared client layer.
|
| 26 |
+
|
| 27 |
+
## Transport model
|
| 28 |
+
|
| 29 |
+
The in-process path uses typed channels:
|
| 30 |
+
|
| 31 |
+
- client -> server: `ClientRequest` / `ClientNotification`
|
| 32 |
+
- server -> client: `InProcessServerEvent`
|
| 33 |
+
- `ServerRequest`
|
| 34 |
+
- `ServerNotification`
|
| 35 |
+
- `LegacyNotification`
|
| 36 |
+
|
| 37 |
+
JSON serialization is still used at external transport boundaries
|
| 38 |
+
(stdio/websocket), but the in-process hot path is typed.
|
| 39 |
+
|
| 40 |
+
Typed requests still receive app-server responses through the JSON-RPC
|
| 41 |
+
result envelope internally. That is intentional: the in-process path is
|
| 42 |
+
meant to preserve app-server semantics while removing the process
|
| 43 |
+
boundary, not to introduce a second response contract.
|
| 44 |
+
|
| 45 |
+
## Bootstrap behavior
|
| 46 |
+
|
| 47 |
+
The client facade starts an already-initialized in-process runtime, but
|
| 48 |
+
thread bootstrap still follows normal app-server flow:
|
| 49 |
+
|
| 50 |
+
- caller sends `thread/start` or `thread/resume`
|
| 51 |
+
- app-server returns the immediate typed response
|
| 52 |
+
- richer session metadata may arrive later as a `SessionConfigured`
|
| 53 |
+
legacy event
|
| 54 |
+
|
| 55 |
+
Surfaces such as TUI and exec may therefore need a short bootstrap
|
| 56 |
+
phase where they reconcile startup response data with later events.
|
| 57 |
+
|
| 58 |
+
## Backpressure and shutdown
|
| 59 |
+
|
| 60 |
+
- Command queues and the embedded runtime remain bounded, using
|
| 61 |
+
`DEFAULT_IN_PROCESS_CHANNEL_CAPACITY` by default.
|
| 62 |
+
- The facade's local consumer event queue is unbounded and preserves notification
|
| 63 |
+
order. This keeps the worker draining the bounded runtime while a caller waits
|
| 64 |
+
for a request, preventing unread notifications from blocking its response.
|
| 65 |
+
- `shutdown()` performs a bounded graceful shutdown and then aborts if timeout
|
| 66 |
+
is exceeded.
|
codex-rs/app-server-daemon/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server-daemon",
|
| 5 |
+
crate_name = "codex_app_server_daemon",
|
| 6 |
+
)
|
codex-rs/app-server-daemon/Cargo.toml
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server-daemon"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_app_server_daemon"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
anyhow = { workspace = true }
|
| 17 |
+
codex-app-server-protocol = { workspace = true }
|
| 18 |
+
codex-app-server-transport = { workspace = true }
|
| 19 |
+
codex-http-client = { workspace = true }
|
| 20 |
+
codex-install-context = { workspace = true }
|
| 21 |
+
codex-utils-home-dir = { workspace = true }
|
| 22 |
+
codex-uds = { workspace = true }
|
| 23 |
+
futures = { workspace = true }
|
| 24 |
+
libc = { workspace = true }
|
| 25 |
+
serde = { workspace = true, features = ["derive"] }
|
| 26 |
+
serde_json = { workspace = true }
|
| 27 |
+
semver = { workspace = true }
|
| 28 |
+
blake3 = { workspace = true }
|
| 29 |
+
tokio = { workspace = true, features = [
|
| 30 |
+
"fs",
|
| 31 |
+
"io-util",
|
| 32 |
+
"macros",
|
| 33 |
+
"process",
|
| 34 |
+
"rt-multi-thread",
|
| 35 |
+
"signal",
|
| 36 |
+
"time",
|
| 37 |
+
] }
|
| 38 |
+
tempfile = { workspace = true }
|
| 39 |
+
tokio-tungstenite = { workspace = true }
|
| 40 |
+
tracing = { workspace = true }
|
| 41 |
+
|
| 42 |
+
[dev-dependencies]
|
| 43 |
+
pretty_assertions = { workspace = true }
|
| 44 |
+
|
| 45 |
+
[target.'cfg(windows)'.dependencies]
|
| 46 |
+
windows-sys = { version = "0.52", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_JobObjects", "Win32_Security", "Win32_Security_Authorization", "Win32_System_Threading"] }
|
codex-rs/app-server-daemon/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# codex-app-server-daemon
|
| 2 |
+
|
| 3 |
+
> `codex-app-server-daemon` is experimental and its lifecycle contract may
|
| 4 |
+
> change while the remote-management flow is still being developed.
|
| 5 |
+
|
| 6 |
+
`codex-app-server-daemon` backs the machine-readable `codex app-server`
|
| 7 |
+
lifecycle commands used by remote clients such as the desktop and mobile apps.
|
| 8 |
+
It is intended for Codex instances launched over SSH, including fresh developer
|
| 9 |
+
machines that should expose app-server with `remote_control` enabled.
|
| 10 |
+
|
| 11 |
+
## Platform support
|
| 12 |
+
|
| 13 |
+
The daemon supports Linux, macOS, and Windows using platform-specific process
|
| 14 |
+
and file-locking primitives. Windows startup requires a non-elevated terminal
|
| 15 |
+
whose host permits detached child processes.
|
| 16 |
+
|
| 17 |
+
Windows automatic attachment requires the canonical socket address to fit the
|
| 18 |
+
108-byte AF_UNIX limit (including its terminator). A short junction alias whose
|
| 19 |
+
resolved address exceeds that limit falls back to the embedded server. Use a
|
| 20 |
+
shorter `CODEX_HOME` to share the daemon; discovery does not trust a mutable alias.
|
| 21 |
+
|
| 22 |
+
Shared clients use the environment inherited when the daemon started. Opening a
|
| 23 |
+
new terminal or clearing variables there does not clear the running daemon's
|
| 24 |
+
environment; per-client environment isolation is not provided.
|
| 25 |
+
An invocation that sets `CODEX_EXEC_SERVER_URL` skips implicit daemon attachment
|
| 26 |
+
so its executor selection is preserved. If an implicitly discovered daemon cannot
|
| 27 |
+
initialize the connection, the TUI starts an embedded server instead. Explicit
|
| 28 |
+
`--remote` endpoints remain authoritative and report connection failures.
|
| 29 |
+
|
| 30 |
+
## Commands
|
| 31 |
+
|
| 32 |
+
```sh
|
| 33 |
+
codex app-server daemon start
|
| 34 |
+
codex app-server daemon restart
|
| 35 |
+
codex app-server daemon update
|
| 36 |
+
codex app-server daemon enable-remote-control
|
| 37 |
+
codex app-server daemon disable-remote-control
|
| 38 |
+
codex app-server daemon stop
|
| 39 |
+
codex app-server daemon version
|
| 40 |
+
codex app-server daemon bootstrap --remote-control
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
On success, every command writes exactly one JSON object to stdout. Consumers
|
| 44 |
+
should parse that JSON rather than relying on human-readable text. Lifecycle
|
| 45 |
+
responses report the resolved backend, socket path, local CLI version, and
|
| 46 |
+
running app-server version when applicable.
|
| 47 |
+
|
| 48 |
+
Eligible managed daemons check for updates after five minutes, then hourly by
|
| 49 |
+
default. Edit `CODEX_HOME/app-server-daemon/settings.json` to change this:
|
| 50 |
+
|
| 51 |
+
```json
|
| 52 |
+
{"remoteControlEnabled": false,
|
| 53 |
+
"shutdownGraceSeconds": 60,
|
| 54 |
+
"updater": {"autoUpdateEnabled": false, "updateIntervalMinutes": 120}}
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
Positive minute intervals have no configured cap. `daemon restart` applies the
|
| 58 |
+
enabled state; the next updater wait reads a new interval. The preference does
|
| 59 |
+
not affect an explicit `codex update` command or `daemon update`.
|
| 60 |
+
|
| 61 |
+
`daemon update` selects the latest stable release, even with automatic updates
|
| 62 |
+
disabled. It also returns pinned or local managed packages to production update
|
| 63 |
+
eligibility, preserving the automatic-update preference. Legacy installations
|
| 64 |
+
migrate to the dedicated root once the published installer and release support
|
| 65 |
+
migration. JSON reports `updated`, `noUpdate`, or `unsupported`, with installed
|
| 66 |
+
and running versions. A running daemon restarts, so active or queued work may be
|
| 67 |
+
interrupted; a stopped daemon stays stopped. Installer errors return nonzero.
|
| 68 |
+
The updater uses saved network settings; CLI `-c` overrides do not reach it.
|
| 69 |
+
|
| 70 |
+
For all managed app-server shutdowns, including explicit stop and restart and
|
| 71 |
+
updater-triggered restarts, `shutdownGraceSeconds` defaults to 60 and accepts
|
| 72 |
+
an integer from 0 through 300. Zero forces shutdown immediately after requesting
|
| 73 |
+
a graceful exit; the five-minute maximum bounds the wait even if a turn is still
|
| 74 |
+
running.
|
| 75 |
+
|
| 76 |
+
## Bootstrap flow
|
| 77 |
+
|
| 78 |
+
For a new Linux or macOS machine:
|
| 79 |
+
|
| 80 |
+
```sh
|
| 81 |
+
curl -fsSL https://chatgpt.com/codex/install.sh | sh
|
| 82 |
+
$HOME/.codex/packages/standalone/current/codex app-server daemon bootstrap --remote-control
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
On Windows, use a non-elevated PowerShell terminal whose host allows breakaway:
|
| 86 |
+
|
| 87 |
+
```powershell
|
| 88 |
+
irm https://chatgpt.com/codex/install.ps1 | iex
|
| 89 |
+
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME '.codex' }
|
| 90 |
+
& "$codexHome\packages\standalone\current\bin\codex.exe" app-server daemon bootstrap --remote-control
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
`bootstrap` can use any complete CLI package. If no daemon package is installed,
|
| 94 |
+
it copies the invoking package into `CODEX_HOME/packages/app-server-daemon` and
|
| 95 |
+
prints an installation message without asking for confirmation. Existing daemon
|
| 96 |
+
packages are reused, including legacy installations; a broken selection is not
|
| 97 |
+
silently replaced. A bare executable cannot supply a new installation.
|
| 98 |
+
|
| 99 |
+
It records the daemon settings under `CODEX_HOME/app-server-daemon/`, starts app-server as a
|
| 100 |
+
pidfile-backed detached process. It launches a detached updater loop when
|
| 101 |
+
automatic updates are enabled, the installer selected the stable `latest`
|
| 102 |
+
channel, and the managed binary supports the updater command.
|
| 103 |
+
|
| 104 |
+
## Installation and update cases
|
| 105 |
+
|
| 106 |
+
New daemons use `CODEX_HOME/packages/app-server-daemon/current/bin/codex`
|
| 107 |
+
(`codex.exe` on Windows). The package contains the executable and its helpers.
|
| 108 |
+
Daemon-only installer updates leave the user's CLI command and shell setup alone.
|
| 109 |
+
|
| 110 |
+
Previously launched legacy daemons retain `CODEX_HOME/packages/standalone/current`,
|
| 111 |
+
including its flat binary layout when present. Starts and scheduled updates keep
|
| 112 |
+
using that location. An explicit production update prepares and validates a
|
| 113 |
+
compatible dedicated package before stopping the legacy updater and daemon,
|
| 114 |
+
selecting the new package, and restarting only a previously running daemon.
|
| 115 |
+
The old CLI package files and selection remain unchanged.
|
| 116 |
+
|
| 117 |
+
| Situation | What starts | Does this daemon fetch new binaries? | Does a running app-server eventually move to a newer binary on its own? |
|
| 118 |
+
| --- | --- | --- | --- |
|
| 119 |
+
| Latest-channel installer has run; `start` or `bootstrap` is used with automatic updates enabled | Managed binary and detached updater when supported | When supported, the platform's installer runs on the configured cadence. | When supported, the running server restarts with the new binary before the updater replaces itself. |
|
| 120 |
+
| Installer selected an explicit release; `bootstrap` is used | Managed binary only | No; the selected release stays pinned. | No; an explicit restart uses the selected binary. |
|
| 121 |
+
| Another tool updates the managed binary | A fresh start or explicit restart uses it; a running server is reused. | Yes, when a latest-channel updater is running, on the configured cadence. | An updater that was running through the change compares binary contents on its next successful installer pass and refreshes the server first. |
|
| 122 |
+
|
| 123 |
+
### Managed packages
|
| 124 |
+
|
| 125 |
+
For dedicated and retained legacy daemon installations:
|
| 126 |
+
|
| 127 |
+
- lifecycle commands use the selected daemon package, regardless of the invoking
|
| 128 |
+
CLI version; they do not implicitly replace an existing package
|
| 129 |
+
- `bootstrap` is supported
|
| 130 |
+
- managed `start`, `restart`, and `bootstrap` ensure a single detached pid-backed
|
| 131 |
+
updater loop only when automatic updates are enabled for a stable latest-channel
|
| 132 |
+
release whose managed binary supports the updater command
|
| 133 |
+
- the installer records the latest-channel selection alongside `current`;
|
| 134 |
+
selecting an explicit release clears it, even if that version is currently
|
| 135 |
+
latest. The updater checks the selection again while holding the install lock
|
| 136 |
+
so an in-flight update cannot override a new pin
|
| 137 |
+
- installs made before the installer recorded channel selections need one new
|
| 138 |
+
`latest` installation to opt into automatic updates; until then the daemon
|
| 139 |
+
continues to serve app-server without updating the selected release
|
| 140 |
+
- after a successful refresh, if app-server is running and the managed binary
|
| 141 |
+
contents changed, the updater restarts app-server with that binary first and
|
| 142 |
+
only then replaces its own process image
|
| 143 |
+
- the updater loop is not reboot-persistent; a managed start after reboot
|
| 144 |
+
starts it again
|
| 145 |
+
|
| 146 |
+
### Out-of-band updates
|
| 147 |
+
|
| 148 |
+
This daemon does not watch arbitrary executable files for replacement. If some
|
| 149 |
+
other tool updates the managed binary path:
|
| 150 |
+
|
| 151 |
+
- an updater that was already running notices a changed managed
|
| 152 |
+
binary on its next successful scheduled installer pass; if
|
| 153 |
+
app-server is running, it refreshes app-server first and then refreshes itself
|
| 154 |
+
once that replacement starts successfully
|
| 155 |
+
- if the updater was absent during a same-version binary replacement, a later
|
| 156 |
+
managed start recovers it but cannot infer the running server's previous
|
| 157 |
+
executable identity; use `codex app-server daemon restart` to refresh the server
|
| 158 |
+
|
| 159 |
+
## Lifecycle semantics
|
| 160 |
+
|
| 161 |
+
`start` is idempotent and returns after app-server is ready to answer the normal
|
| 162 |
+
JSON-RPC initialize handshake on the Unix control socket.
|
| 163 |
+
|
| 164 |
+
`restart` stops any managed daemon and starts it again.
|
| 165 |
+
|
| 166 |
+
`enable-remote-control` and `disable-remote-control` persist the launch setting
|
| 167 |
+
for future starts. If a managed app-server is already running, they restart it
|
| 168 |
+
so the new setting takes effect immediately.
|
| 169 |
+
|
| 170 |
+
Top-level `codex remote-control start` enables and persists remote control for
|
| 171 |
+
the managed daemon, overriding a saved disabled value. It starts or bootstraps
|
| 172 |
+
the daemon as needed. Plain `codex remote-control` runs a separate foreground
|
| 173 |
+
server and does not change daemon settings; `codex remote-control stop` stops
|
| 174 |
+
the managed daemon without clearing its saved remote-control preference.
|
| 175 |
+
`daemon start` and `daemon restart` use that saved preference. `daemon bootstrap`
|
| 176 |
+
sets it according to `--remote-control` (disabled when omitted).
|
| 177 |
+
|
| 178 |
+
`stop` sends a graceful termination request first, then force-terminates the
|
| 179 |
+
process after the configured grace window if it is still alive.
|
| 180 |
+
|
| 181 |
+
All mutating lifecycle commands are serialized per `CODEX_HOME`, so a concurrent
|
| 182 |
+
`start`, `restart`, `enable-remote-control`, `disable-remote-control`, `stop`,
|
| 183 |
+
or `bootstrap` does not race another in-flight lifecycle operation.
|
| 184 |
+
|
| 185 |
+
## State
|
| 186 |
+
|
| 187 |
+
The daemon stores its local state under `CODEX_HOME/app-server-daemon/`:
|
| 188 |
+
|
| 189 |
+
- `settings.json` for remote-control launch settings and updater preferences
|
| 190 |
+
- `app-server.pid` for the app-server process record
|
| 191 |
+
- `app-server-updater.pid` for the pid-backed standalone updater loop
|
| 192 |
+
- `daemon.lock` for daemon-wide lifecycle serialization
|
codex-rs/app-server-protocol-noop-macros/BUILD.bazel
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server-protocol-noop-macros",
|
| 5 |
+
crate_name = "codex_app_server_protocol_noop_macros",
|
| 6 |
+
proc_macro = True,
|
| 7 |
+
)
|
codex-rs/app-server-protocol-noop-macros/Cargo.toml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server-protocol-noop-macros"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
proc-macro = true
|
| 9 |
+
test = false
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
codex-rs/app-server-protocol/BUILD.bazel
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server-protocol",
|
| 5 |
+
compile_data = glob(["schema/precomputed/**"]),
|
| 6 |
+
crate_name = "codex_app_server_protocol",
|
| 7 |
+
test_data_extra = glob(
|
| 8 |
+
["schema/**"],
|
| 9 |
+
allow_empty = True,
|
| 10 |
+
),
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
alias(
|
| 14 |
+
name = "schema-generator",
|
| 15 |
+
testonly = True,
|
| 16 |
+
actual = ":app-server-protocol-unit-tests-bin",
|
| 17 |
+
tags = ["manual"],
|
| 18 |
+
visibility = ["//bazel/schema:__pkg__"],
|
| 19 |
+
)
|
codex-rs/app-server-protocol/Cargo.toml
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server-protocol"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_app_server_protocol"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
anyhow = { workspace = true }
|
| 17 |
+
codex-experimental-api-macros = { workspace = true }
|
| 18 |
+
codex-app-server-protocol-noop-macros = { workspace = true }
|
| 19 |
+
codex-extension-items = { workspace = true }
|
| 20 |
+
codex-history = { workspace = true }
|
| 21 |
+
codex-protocol = { workspace = true }
|
| 22 |
+
codex-rollout = { workspace = true }
|
| 23 |
+
codex-secrets = { workspace = true }
|
| 24 |
+
codex-shell-command = { workspace = true }
|
| 25 |
+
codex-utils-absolute-path = { workspace = true }
|
| 26 |
+
codex-utils-path-uri = { workspace = true }
|
| 27 |
+
codex-utils-redacted-string = { workspace = true }
|
| 28 |
+
serde = { workspace = true, features = ["derive"] }
|
| 29 |
+
serde_json = { workspace = true }
|
| 30 |
+
serde_with = { workspace = true }
|
| 31 |
+
strum_macros = { workspace = true }
|
| 32 |
+
thiserror = { workspace = true }
|
| 33 |
+
rmcp = { workspace = true, default-features = false, features = [
|
| 34 |
+
"base64",
|
| 35 |
+
"macros",
|
| 36 |
+
"server",
|
| 37 |
+
] }
|
| 38 |
+
inventory = { workspace = true }
|
| 39 |
+
tracing = { workspace = true }
|
| 40 |
+
uuid = { workspace = true, features = ["serde", "v7"] }
|
| 41 |
+
zstd = { workspace = true }
|
| 42 |
+
|
| 43 |
+
[dev-dependencies]
|
| 44 |
+
anyhow = { workspace = true }
|
| 45 |
+
codex-utils-cargo-bin = { workspace = true }
|
| 46 |
+
pretty_assertions = { workspace = true }
|
| 47 |
+
rmcp = { workspace = true, default-features = false, features = [
|
| 48 |
+
"base64",
|
| 49 |
+
"macros",
|
| 50 |
+
"schemars",
|
| 51 |
+
"server",
|
| 52 |
+
] }
|
| 53 |
+
schemars = { workspace = true }
|
| 54 |
+
similar = { workspace = true }
|
| 55 |
+
tempfile = { workspace = true }
|
| 56 |
+
ts-rs = { workspace = true }
|
codex-rs/app-server-test-client/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server-test-client",
|
| 5 |
+
crate_name = "codex_app_server_test_client",
|
| 6 |
+
)
|
codex-rs/app-server-test-client/Cargo.toml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server-test-client"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lints]
|
| 8 |
+
workspace = true
|
| 9 |
+
|
| 10 |
+
[dependencies]
|
| 11 |
+
anyhow = { workspace = true }
|
| 12 |
+
clap = { workspace = true, features = ["derive", "env"] }
|
| 13 |
+
codex-app-server-protocol = { workspace = true }
|
| 14 |
+
codex-core = { workspace = true }
|
| 15 |
+
codex-otel = { workspace = true }
|
| 16 |
+
codex-protocol = { workspace = true }
|
| 17 |
+
codex-utils-cli = { workspace = true }
|
| 18 |
+
serde = { workspace = true, features = ["derive"] }
|
| 19 |
+
serde_json = { workspace = true }
|
| 20 |
+
tokio = { workspace = true, features = ["rt"] }
|
| 21 |
+
tracing = { workspace = true }
|
| 22 |
+
tracing-subscriber = { workspace = true }
|
| 23 |
+
tungstenite = { workspace = true }
|
| 24 |
+
url = { workspace = true }
|
| 25 |
+
uuid = { workspace = true, features = ["v4"] }
|
| 26 |
+
|
| 27 |
+
[lib]
|
| 28 |
+
doctest = false
|
| 29 |
+
|
| 30 |
+
[dev-dependencies]
|
| 31 |
+
pretty_assertions = { workspace = true }
|
codex-rs/app-server-test-client/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# App Server Test Client
|
| 2 |
+
Quickstart for running and hitting `codex app-server`.
|
| 3 |
+
|
| 4 |
+
## Quickstart
|
| 5 |
+
|
| 6 |
+
Run from `<reporoot>/codex-rs`.
|
| 7 |
+
|
| 8 |
+
```bash
|
| 9 |
+
# 1) Build debug codex binary
|
| 10 |
+
cargo build -p codex-cli --bin codex
|
| 11 |
+
|
| 12 |
+
# 2) Start websocket app-server in background
|
| 13 |
+
cargo run -p codex-app-server-test-client -- \
|
| 14 |
+
--codex-bin ./target/debug/codex \
|
| 15 |
+
serve --listen ws://127.0.0.1:4222 --kill
|
| 16 |
+
|
| 17 |
+
# 3) Call app-server (defaults to ws://127.0.0.1:4222)
|
| 18 |
+
cargo run -p codex-app-server-test-client -- model-list
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
`send-message` and `send-message-v2` handle `request_user_input` server requests interactively.
|
| 22 |
+
When Codex asks a question, choose a numbered option (or `o` for a free-form answer when offered)
|
| 23 |
+
and the client will send the response and continue streaming the same turn.
|
| 24 |
+
|
| 25 |
+
## Testing Codex-managed Amazon Bedrock login
|
| 26 |
+
|
| 27 |
+
`test-login --amazon-bedrock` initializes the experimental app-server API, sends an
|
| 28 |
+
`account/login/start` request with an Amazon Bedrock API key, and waits for the
|
| 29 |
+
`account/login/completed` and `account/updated` notifications. Login replaces the current primary
|
| 30 |
+
credential and sets `model_provider = "amazon-bedrock"`, so use an isolated `CODEX_HOME` when
|
| 31 |
+
testing.
|
| 32 |
+
|
| 33 |
+
```bash
|
| 34 |
+
export CODEX_HOME="$(mktemp -d)"
|
| 35 |
+
printf 'cli_auth_credentials_store = "file"\n' > "$CODEX_HOME/config.toml"
|
| 36 |
+
|
| 37 |
+
cargo build -p codex-cli --bin codex
|
| 38 |
+
cargo run -p codex-app-server-test-client -- \
|
| 39 |
+
--codex-bin ./target/debug/codex \
|
| 40 |
+
test-login \
|
| 41 |
+
--amazon-bedrock \
|
| 42 |
+
--api-key "<BEDROCK_API_KEY>" \
|
| 43 |
+
--region us-west-2
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
The test client redacts `apiKey` from its outbound request log. After login, start a fresh Codex
|
| 47 |
+
process with the same `CODEX_HOME` to verify that it uses the persisted managed credential.
|
| 48 |
+
|
| 49 |
+
## Testing logout
|
| 50 |
+
|
| 51 |
+
`test-logout` initializes the app-server, sends an `account/logout` request, and waits for the
|
| 52 |
+
resulting `account/updated` notification. It uses the active `CODEX_HOME`, so point it at an
|
| 53 |
+
isolated directory when testing credential cleanup.
|
| 54 |
+
|
| 55 |
+
```bash
|
| 56 |
+
cargo run -p codex-app-server-test-client -- \
|
| 57 |
+
--codex-bin ./target/debug/codex \
|
| 58 |
+
test-logout
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## Testing Plugin Analytics
|
| 62 |
+
|
| 63 |
+
The `plugin-analytics-smoke` command exercises `plugin/installed`, plugin
|
| 64 |
+
enable/disable config writes, and a structured plugin mention through one
|
| 65 |
+
app-server connection. Analytics are captured to a local JSONL file and are
|
| 66 |
+
not sent to the analytics backend. The model turn uses a loopback Responses
|
| 67 |
+
API server.
|
| 68 |
+
|
| 69 |
+
The selected plugin must already be installed and enabled remotely, and the
|
| 70 |
+
active Codex profile must be authenticated. On a fresh local cache, the command
|
| 71 |
+
retries ephemeral turns while the installed remote bundle finishes syncing.
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
# Build a debug Codex binary; analytics capture is unavailable in release builds.
|
| 75 |
+
cargo build -p codex-cli --bin codex
|
| 76 |
+
|
| 77 |
+
cargo run -p codex-app-server-test-client -- \
|
| 78 |
+
--codex-bin ./target/debug/codex \
|
| 79 |
+
plugin-analytics-smoke \
|
| 80 |
+
--plugin-id linear@openai-curated-remote
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
Use `--capture-file /tmp/plugin-analytics.jsonl` to select the output path.
|
| 84 |
+
The command validates one `codex_plugin_disabled`, `codex_plugin_enabled`, and
|
| 85 |
+
`codex_plugin_used` event with the expected local and remote plugin identities
|
| 86 |
+
and capability metadata. Each event includes the local ID in `plugin_id` and the
|
| 87 |
+
backend ID in `remote_plugin_id`. The enabled and disabled events come from
|
| 88 |
+
successful writes to the temporary config; the command does not mutate the
|
| 89 |
+
remote enabled state. It prints the events and leaves the JSONL file in place
|
| 90 |
+
for inspection. It does not install or uninstall plugins and does not modify
|
| 91 |
+
the profile's persistent config.
|
| 92 |
+
|
| 93 |
+
### Testing remote install and uninstall analytics
|
| 94 |
+
|
| 95 |
+
`plugin-analytics-mutation-smoke` is a manually invoked live smoke test. It
|
| 96 |
+
contacts the configured remote plugin API and temporarily changes the active
|
| 97 |
+
account's installed-plugin state. It is not run by `cargo test`, `just test`,
|
| 98 |
+
or CI.
|
| 99 |
+
|
| 100 |
+
Choose a remote plugin that is available to the active account and is not
|
| 101 |
+
currently installed. The command refuses to run when the plugin is already
|
| 102 |
+
installed, installs it, validates `codex_plugin_installed`, uninstalls it, and
|
| 103 |
+
validates `codex_plugin_uninstalled`, and verifies that the original
|
| 104 |
+
uninstalled state was restored.
|
| 105 |
+
|
| 106 |
+
The mutation events include the local Codex ID in `plugin_id` and the backend ID
|
| 107 |
+
in `remote_plugin_id`.
|
| 108 |
+
|
| 109 |
+
`--remote-plugin-id` takes the backend ID, such as `plugins~Plugin_...`, not the
|
| 110 |
+
local `<plugin>@<marketplace>` ID.
|
| 111 |
+
|
| 112 |
+
```bash
|
| 113 |
+
cargo run -p codex-app-server-test-client -- \
|
| 114 |
+
--codex-bin ./target/debug/codex \
|
| 115 |
+
plugin-analytics-mutation-smoke \
|
| 116 |
+
--remote-plugin-id <REMOTE_PLUGIN_ID> \
|
| 117 |
+
--confirm-account-mutation \
|
| 118 |
+
--capture-file /tmp/plugin-mutation-analytics.jsonl
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
Analytics use the normal queue, reduction, batching, and serialization path,
|
| 122 |
+
but the debug capture destination suppresses analytics network delivery. The
|
| 123 |
+
command prints one of these final states:
|
| 124 |
+
|
| 125 |
+
- `PASS`: the install and uninstall events validated and the plugin is uninstalled.
|
| 126 |
+
- `FAIL-CLEAN`: validation failed, but the original uninstalled state was
|
| 127 |
+
restored.
|
| 128 |
+
- `FAIL-LOCAL-CACHE`: the backend is uninstalled, but local cleanup reported
|
| 129 |
+
an error.
|
| 130 |
+
- `FAIL-DIRTY`: cleanup failed and the plugin still appears installed.
|
| 131 |
+
- `FAIL-UNKNOWN`: the command could not verify the final installed state.
|
| 132 |
+
|
| 133 |
+
For a dirty or uncertain result, retry cleanup with:
|
| 134 |
+
|
| 135 |
+
```bash
|
| 136 |
+
cargo run -p codex-app-server-test-client -- \
|
| 137 |
+
--codex-bin ./target/debug/codex \
|
| 138 |
+
plugin-remote-uninstall \
|
| 139 |
+
--remote-plugin-id <REMOTE_PLUGIN_ID> \
|
| 140 |
+
--confirm-account-mutation
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
Cleanup does not require analytics capture or a debug Codex binary. When the
|
| 144 |
+
smoke uses global `--config` overrides, its printed recovery command preserves
|
| 145 |
+
them so cleanup targets the same backend and account.
|
| 146 |
+
|
| 147 |
+
## Watching Raw Inbound Traffic
|
| 148 |
+
|
| 149 |
+
Initialize a connection, then print every inbound JSON-RPC message until you stop it with
|
| 150 |
+
`Ctrl+C`:
|
| 151 |
+
|
| 152 |
+
```bash
|
| 153 |
+
cargo run -p codex-app-server-test-client -- watch
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
## Testing Thread Rejoin Behavior
|
| 157 |
+
|
| 158 |
+
Build and start an app server using commands above. The app-server log is written to `/tmp/codex-app-server-test-client/app-server.log`
|
| 159 |
+
|
| 160 |
+
### 1) Get a thread id
|
| 161 |
+
|
| 162 |
+
Create at least one thread, then list threads:
|
| 163 |
+
|
| 164 |
+
```bash
|
| 165 |
+
cargo run -p codex-app-server-test-client -- send-message-v2 "seed thread for rejoin test"
|
| 166 |
+
cargo run -p codex-app-server-test-client -- thread-list --limit 5
|
| 167 |
+
```
|
| 168 |
+
|
| 169 |
+
Copy a thread id from the `thread-list` output.
|
| 170 |
+
|
| 171 |
+
### 2) Rejoin while a turn is in progress (two terminals)
|
| 172 |
+
|
| 173 |
+
Terminal A:
|
| 174 |
+
|
| 175 |
+
```bash
|
| 176 |
+
cargo run --bin codex-app-server-test-client -- \
|
| 177 |
+
resume-message-v2 <THREAD_ID> "respond with thorough docs on the rust core"
|
| 178 |
+
```
|
| 179 |
+
|
| 180 |
+
Terminal B (while Terminal A is still streaming):
|
| 181 |
+
|
| 182 |
+
```bash
|
| 183 |
+
cargo run --bin codex-app-server-test-client -- thread-resume <THREAD_ID>
|
| 184 |
+
```
|
codex-rs/app-server/BUILD.bazel
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "app-server",
|
| 5 |
+
crate_name = "codex_app_server",
|
| 6 |
+
extra_binaries = [
|
| 7 |
+
"//codex-rs/bwrap:bwrap",
|
| 8 |
+
"//codex-rs/code-mode-host:codex-code-mode-host",
|
| 9 |
+
"//codex-rs/rmcp-client:test_stdio_server",
|
| 10 |
+
],
|
| 11 |
+
extra_binaries_non_windows = [
|
| 12 |
+
"//codex-rs/cli:codex",
|
| 13 |
+
],
|
| 14 |
+
integration_test_timeout = "long",
|
| 15 |
+
run_tests_with_wine_exec = True,
|
| 16 |
+
test_shard_counts = {
|
| 17 |
+
# Note app-server-all-test has a large number of integration tests, so
|
| 18 |
+
# even a single shard can be quite slow. When there is a legitimate
|
| 19 |
+
# test failure in a shard, it will still get run 3x in total, which
|
| 20 |
+
# can cause us to exhaust our CI timeout if the shard happens to run
|
| 21 |
+
# long. Using a higher shard count for app-server-all-test should help
|
| 22 |
+
# mitigate this risk.
|
| 23 |
+
"app-server-all-test": 16,
|
| 24 |
+
"app-server-unit-tests": 8,
|
| 25 |
+
},
|
| 26 |
+
test_tags = ["no-sandbox"],
|
| 27 |
+
test_threads = select({
|
| 28 |
+
"@platforms//os:macos": 1,
|
| 29 |
+
"//conditions:default": 0,
|
| 30 |
+
}),
|
| 31 |
+
)
|
codex-rs/app-server/Cargo.toml
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-app-server"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[[bin]]
|
| 8 |
+
name = "codex-app-server"
|
| 9 |
+
path = "src/main.rs"
|
| 10 |
+
|
| 11 |
+
[[bin]]
|
| 12 |
+
name = "codex-app-server-test-notify-capture"
|
| 13 |
+
path = "src/bin/notify_capture.rs"
|
| 14 |
+
|
| 15 |
+
[[bin]]
|
| 16 |
+
name = "exec-server"
|
| 17 |
+
path = "src/bin/exec_server.rs"
|
| 18 |
+
|
| 19 |
+
[lib]
|
| 20 |
+
name = "codex_app_server"
|
| 21 |
+
path = "src/lib.rs"
|
| 22 |
+
doctest = false
|
| 23 |
+
|
| 24 |
+
[lints]
|
| 25 |
+
workspace = true
|
| 26 |
+
|
| 27 |
+
[dependencies]
|
| 28 |
+
anyhow = { workspace = true }
|
| 29 |
+
base64 = { workspace = true }
|
| 30 |
+
axum = { workspace = true, default-features = false, features = [
|
| 31 |
+
"http1",
|
| 32 |
+
"json",
|
| 33 |
+
"tokio",
|
| 34 |
+
"ws",
|
| 35 |
+
] }
|
| 36 |
+
codex-analytics = { workspace = true }
|
| 37 |
+
codex-agent-extension = { workspace = true }
|
| 38 |
+
codex-arg0 = { workspace = true }
|
| 39 |
+
codex-aws-auth = { workspace = true }
|
| 40 |
+
codex-cloud-config = { workspace = true }
|
| 41 |
+
codex-code-mode = { workspace = true }
|
| 42 |
+
codex-config = { workspace = true }
|
| 43 |
+
codex-network-proxy = { workspace = true }
|
| 44 |
+
codex-connectors = { workspace = true }
|
| 45 |
+
codex-core = { workspace = true }
|
| 46 |
+
codex-core-plugins = { workspace = true }
|
| 47 |
+
codex-diagnostics = { workspace = true }
|
| 48 |
+
codex-home = { workspace = true }
|
| 49 |
+
codex-exec-server = { workspace = true }
|
| 50 |
+
codex-extension-api = { workspace = true }
|
| 51 |
+
codex-external-agent-migration = { workspace = true }
|
| 52 |
+
codex-features = { workspace = true }
|
| 53 |
+
codex-goal-extension = { workspace = true }
|
| 54 |
+
codex-git-attribution = { workspace = true }
|
| 55 |
+
codex-guardian-v2 = { workspace = true }
|
| 56 |
+
codex-git-utils = { workspace = true }
|
| 57 |
+
codex-file-watcher = { workspace = true }
|
| 58 |
+
codex-hooks = { workspace = true }
|
| 59 |
+
codex-history-notes-extension = { workspace = true }
|
| 60 |
+
codex-http-client = { workspace = true }
|
| 61 |
+
codex-otel = { workspace = true }
|
| 62 |
+
codex-plugin = { workspace = true }
|
| 63 |
+
codex-shell-command = { workspace = true }
|
| 64 |
+
codex-skills = { workspace = true }
|
| 65 |
+
codex-skills-extension = { workspace = true }
|
| 66 |
+
codex-utils-cli = { workspace = true }
|
| 67 |
+
codex-user-verification = { workspace = true }
|
| 68 |
+
codex-utils-pty = { workspace = true }
|
| 69 |
+
codex-backend-client = { workspace = true }
|
| 70 |
+
codex-file-search = { workspace = true }
|
| 71 |
+
codex-chatgpt = { workspace = true }
|
| 72 |
+
codex-login = { workspace = true }
|
| 73 |
+
codex-image-generation-extension = { workspace = true }
|
| 74 |
+
codex-memories-extension = { workspace = true }
|
| 75 |
+
codex-web-search-extension = { workspace = true }
|
| 76 |
+
codex-memories-write = { workspace = true }
|
| 77 |
+
codex-mcp = { workspace = true }
|
| 78 |
+
codex-mcp-extension = { workspace = true }
|
| 79 |
+
codex-model-provider = { workspace = true }
|
| 80 |
+
codex-model-provider-info = { workspace = true }
|
| 81 |
+
codex-models-manager = { workspace = true }
|
| 82 |
+
codex-protocol = { workspace = true }
|
| 83 |
+
codex-queue-extension = { workspace = true }
|
| 84 |
+
codex-app-server-protocol = { workspace = true }
|
| 85 |
+
codex-app-server-transport = { workspace = true }
|
| 86 |
+
codex-feedback = { workspace = true }
|
| 87 |
+
codex-rmcp-client = { workspace = true }
|
| 88 |
+
codex-rollout = { workspace = true }
|
| 89 |
+
codex-sandboxing = { workspace = true }
|
| 90 |
+
codex-state = { workspace = true }
|
| 91 |
+
codex-thread-store = { workspace = true }
|
| 92 |
+
codex-tools = { workspace = true }
|
| 93 |
+
codex-utils-absolute-path = { workspace = true }
|
| 94 |
+
codex-utils-json-to-toml = { workspace = true }
|
| 95 |
+
codex-utils-path-uri = { workspace = true }
|
| 96 |
+
chrono = { workspace = true }
|
| 97 |
+
clap = { workspace = true, features = ["derive"] }
|
| 98 |
+
futures = { workspace = true }
|
| 99 |
+
serde = { workspace = true, features = ["derive"] }
|
| 100 |
+
serde_json = { workspace = true }
|
| 101 |
+
sha2 = { workspace = true }
|
| 102 |
+
tempfile = { workspace = true }
|
| 103 |
+
thiserror = { workspace = true }
|
| 104 |
+
time = { workspace = true }
|
| 105 |
+
toml = { workspace = true }
|
| 106 |
+
toml_edit = { workspace = true }
|
| 107 |
+
tokio = { workspace = true, features = [
|
| 108 |
+
"io-std",
|
| 109 |
+
"macros",
|
| 110 |
+
"process",
|
| 111 |
+
"rt-multi-thread",
|
| 112 |
+
"signal",
|
| 113 |
+
] }
|
| 114 |
+
tokio-util = { workspace = true }
|
| 115 |
+
tracing = { workspace = true, features = ["log"] }
|
| 116 |
+
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json"] }
|
| 117 |
+
url = { workspace = true }
|
| 118 |
+
uuid = { workspace = true, features = ["serde", "v7"] }
|
| 119 |
+
|
| 120 |
+
[target.'cfg(all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
|
| 121 |
+
tikv-jemallocator = { workspace = true }
|
| 122 |
+
|
| 123 |
+
[target.'cfg(windows)'.dependencies]
|
| 124 |
+
codex-windows-sandbox = { workspace = true }
|
| 125 |
+
|
| 126 |
+
[dev-dependencies]
|
| 127 |
+
codex-uds = { workspace = true }
|
| 128 |
+
app_test_support = { workspace = true }
|
| 129 |
+
axum = { workspace = true, default-features = false, features = [
|
| 130 |
+
"http1",
|
| 131 |
+
"json",
|
| 132 |
+
"tokio",
|
| 133 |
+
] }
|
| 134 |
+
base64 = { workspace = true }
|
| 135 |
+
codex-utils-cargo-bin = { workspace = true }
|
| 136 |
+
core_test_support = { workspace = true }
|
| 137 |
+
flate2 = { workspace = true }
|
| 138 |
+
hmac = { workspace = true }
|
| 139 |
+
http = { workspace = true }
|
| 140 |
+
opentelemetry = { workspace = true }
|
| 141 |
+
opentelemetry_sdk = { workspace = true }
|
| 142 |
+
pretty_assertions = { workspace = true }
|
| 143 |
+
rmcp = { workspace = true, default-features = false, features = [
|
| 144 |
+
"elicitation",
|
| 145 |
+
"server",
|
| 146 |
+
"transport-streamable-http-server",
|
| 147 |
+
] }
|
| 148 |
+
serial_test = { workspace = true }
|
| 149 |
+
shlex = { workspace = true }
|
| 150 |
+
sqlx = { workspace = true }
|
| 151 |
+
tar = { workspace = true }
|
| 152 |
+
test-case = "3.3.1"
|
| 153 |
+
tokio-tungstenite = { workspace = true }
|
| 154 |
+
tracing-opentelemetry = { workspace = true }
|
| 155 |
+
wiremock = { workspace = true }
|
codex-rs/app-server/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MCP App UI
|
| 2 |
+
|
| 3 |
+
`mcpToolCall.mcpAppUi` records the invoked descriptor's `resourceUri`
|
| 4 |
+
and `preferredModelDisplayMode` (`inline` or `fullscreen`). Descriptors with a widget
|
| 5 |
+
URI default to `inline` when the preference is missing or unsupported. The
|
| 6 |
+
UI information is preserved in tool-call events and saved history so clients can
|
| 7 |
+
render without waiting for the full MCP catalog.
|
| 8 |
+
|
| 9 |
+
The field is null for older history and tools that declare widgets only in
|
| 10 |
+
result metadata; clients retain catalog discovery for those calls. Existing
|
| 11 |
+
resource URI fields remain available for older clients.
|
| 12 |
+
|
| 13 |
+
# Initial Daybreak choice (experimental)
|
| 14 |
+
|
| 15 |
+
Persistent threads accept `daybreakEnabled` on `thread/start` with the
|
| 16 |
+
`experimentalApi` opt-in. The response and `thread/started` notification both
|
| 17 |
+
include the initial choice in `thread.daybreakEnabled`. The choice is staged
|
| 18 |
+
with the thread's other initial metadata and saved when the thread is persisted.
|
| 19 |
+
An unused thread is not guaranteed to survive restart. Omitted or null leaves
|
| 20 |
+
the choice unset. Ephemeral threads cannot save it.
|
| 21 |
+
Use `thread/metadata/update` for later changes. This preference does not select
|
| 22 |
+
`turn/start.cyberAccessProgram` or grant access to an access program.
|
| 23 |
+
|
| 24 |
+
# User verification cancellation (experimental)
|
| 25 |
+
|
| 26 |
+
Local UI clients can cancel a native user-verification RPC by sending
|
| 27 |
+
`userVerification/cancel` with `{requestId}` and the `experimentalApi` opt-in.
|
| 28 |
+
The result is an empty acknowledgment (`{}`). This API does not enable desktop
|
| 29 |
+
verification capability advertisement.
|
| 30 |
+
|
| 31 |
+
`requestId` is the original status, enroll, delete, or verify RPC's string or
|
| 32 |
+
integer ID on the same connection, not the server elicitation ID. Use fresh IDs
|
| 33 |
+
for each operation and a distinct ID for the cancel RPC. Unknown, finished,
|
| 34 |
+
unrelated, and other-connection requests are no-ops.
|
| 35 |
+
|
| 36 |
+
The acknowledgment confirms the cancellation signal without waiting for the OS
|
| 37 |
+
prompt to close. The original RPC completes independently, with
|
| 38 |
+
`cancelled/interrupted` when cancellation prevents completion. Cancellation
|
| 39 |
+
cannot roll back completed effects. It remains effective while a proof waits for
|
| 40 |
+
outbound queue capacity, but cannot retract a response already enqueued.
|
| 41 |
+
|
| 42 |
+
Canceling or resolving an elicitation does not itself stop a separate
|
| 43 |
+
`userVerification/verify` RPC. Clients must cancel that RPC separately and discard
|
| 44 |
+
late proofs after the approval is canceled or resolved. Only one native worker
|
| 45 |
+
runs per app-server; if an OS call remains active after cancellation or timeout,
|
| 46 |
+
subsequent local operations return `failed/providerError` until that worker exits.
|
| 47 |
+
|
| 48 |
+
# Hosted Codex Apps MCP protocol
|
| 49 |
+
|
| 50 |
+
The host-owned HTTP `codex_apps` server uses Legacy by default in app-server and
|
| 51 |
+
standalone Codex. To discover the 2026-07-28 protocol, set
|
| 52 |
+
`codex_apps_mcp_2026_07_28 = true` under `[features]`, or send a true runtime
|
| 53 |
+
override via `experimentalFeature/enablement/set`. Discovery falls back to Legacy
|
| 54 |
+
when the server does not support it. Explicit config takes precedence.
|
| 55 |
+
The dedicated setting does not apply to third-party HTTP or local `codex_app`
|
| 56 |
+
stdio servers. The existing `mcp_2026_07_28` flag still governs eligible other
|
| 57 |
+
servers, regardless of whether their names or URLs resemble hosted Apps.
|
| 58 |
+
App-server does not persist this selection.
|
| 59 |
+
|
| 60 |
+
# Thread removal
|
| 61 |
+
|
| 62 |
+
`thread/archive` and `thread/delete` reject attempts to remove a live internal
|
| 63 |
+
worker with JSON-RPC error `-32600`. The worker's owner controls its shutdown.
|
| 64 |
+
For example, a Guardian reviewer remains available to its parent conversation
|
| 65 |
+
after a client tries to archive or delete it.
|
| 66 |
+
|
| 67 |
+
After the owner releases the worker, its saved conversation can be archived or
|
| 68 |
+
deleted normally. Ordinary client-controlled threads keep their existing behavior.
|
| 69 |
+
|
| 70 |
+
## User verification (experimental)
|
| 71 |
+
|
| 72 |
+
Codex app-server advertises `openai/elicitation.userVerification` to the
|
| 73 |
+
host-owned plugin service for bundled, in-process TUI sessions (`codex-tui`) and
|
| 74 |
+
local stdio desktop sessions (`Codex Desktop`) on devices with supported biometric
|
| 75 |
+
hardware and the `experimentalApi` opt-in. This is an app-server decision,
|
| 76 |
+
independent of whether a key exists; TUI/Desktop/mobile do not advertise this MCP
|
| 77 |
+
capability. Mobile integration requires a separate rollout. Other clients and
|
| 78 |
+
network connections do not receive this mode, even with a recognized client name.
|
| 79 |
+
Before sending verification requests to desktop sessions, deploy a GUI that
|
| 80 |
+
handles the typed verification request, cancellation, and late proofs. The general
|
| 81 |
+
`experimentalApi` opt-in does not identify a compatible GUI version.
|
| 82 |
+
|
| 83 |
+
Local UI clients use five methods. They require the existing
|
| 84 |
+
`experimentalApi` opt-in. The local provider reports
|
| 85 |
+
`unavailable/providerUnavailable` on unsupported platforms or without the required
|
| 86 |
+
ChatGPT account identity.
|
| 87 |
+
|
| 88 |
+
| Method | Params | Result |
|
| 89 |
+
| --- | --- | --- |
|
| 90 |
+
| `userVerification/status` | `{}` | `{credentialId, unavailableReason, unavailableMessage}` |
|
| 91 |
+
| `userVerification/enroll` | `{}` | `{credentialId, algorithm?, publicKey?}` |
|
| 92 |
+
| `userVerification/delete` | `{}` | `{}` |
|
| 93 |
+
| `userVerification/verify` | `{challenge, title, description}` | `{proof: {credentialId, signature}}` |
|
| 94 |
+
| `userVerification/cancel` | `{requestId}` | `{}` |
|
| 95 |
+
|
| 96 |
+
Status reads local readiness without prompting or contacting a backend. A null
|
| 97 |
+
`unavailableReason` means local checks passed, not that registration is valid.
|
| 98 |
+
Unsupported platforms and missing account identity are reported in the status
|
| 99 |
+
response's `unavailableReason` field.
|
| 100 |
+
Enrollment creates or reuses the local key and returns its public metadata. The
|
| 101 |
+
`publicKey` is unpadded base64url SPKI-DER; `algorithm` is `ecdsaP256Sha256X962`.
|
| 102 |
+
During the experimental rollout, `algorithm` and `publicKey` are optional for
|
| 103 |
+
compatibility with older app-servers. Current servers populate both fields;
|
| 104 |
+
callers must check that both are present and non-null before backend registration.
|
| 105 |
+
The trusted UI host owns backend registration: obtain an enrollment challenge,
|
| 106 |
+
sign it with `userVerification/verify`, check that the proof's `credentialId`
|
| 107 |
+
matches this response, and submit the public metadata and proof to the backend.
|
| 108 |
+
Local success is not server enrollment. The caller must preserve the authenticated
|
| 109 |
+
account across this flow and reconcile uncertain registration before retrying.
|
| 110 |
+
Deletion removes the local key; the caller owns backend revocation.
|
| 111 |
+
Enrollment and deletion coordinate credential lifecycle; callers do not issue
|
| 112 |
+
separate generate or rotate commands. Identity comes from the authenticated
|
| 113 |
+
account; this API exposes no caller-selected scope.
|
| 114 |
+
|
| 115 |
+
Verify signs 1–4096 decoded challenge bytes using P-256 ECDSA with SHA-256. The
|
| 116 |
+
challenge and DER signature use unpadded base64url. Title is 1–256 UTF-8 bytes;
|
| 117 |
+
description is at most 4096 bytes. The UI obtains approval for that display
|
| 118 |
+
context before calling. Verify does not require a pending elicitation; a UI with
|
| 119 |
+
its own authenticator can return proof directly in elicitation response content.
|
| 120 |
+
The calling flow owns pending-request checks and discards late proofs.
|
| 121 |
+
Native enroll, delete, and verify accept local stdio and in-process connections.
|
| 122 |
+
WebSocket and remote-control peers must use their own device authenticator;
|
| 123 |
+
status remains available for local readiness. Dropping an embedded RPC, disconnecting,
|
| 124 |
+
or changing authentication cancels its native operation. Responses recheck the
|
| 125 |
+
captured identity after waiting for outbound queue capacity.
|
| 126 |
+
Canceling or resolving an elicitation does not itself stop a separate
|
| 127 |
+
`userVerification/verify` RPC. The GUI must use `userVerification/cancel` to
|
| 128 |
+
cancel that RPC and discard late proofs when an approval is canceled or resolved.
|
| 129 |
+
See [User verification cancellation](#user-verification-cancellation-experimental)
|
| 130 |
+
for request ID and acknowledgment semantics.
|
| 131 |
+
Only one native worker runs per app-server. If an OS call remains active after
|
| 132 |
+
cancellation or timeout, subsequent local operations return `failed/providerError`
|
| 133 |
+
until that worker exits.
|
| 134 |
+
|
| 135 |
+
Failures use the normal JSON-RPC error envelope with closed `{type, reason}` data:
|
| 136 |
+
`invalidRequest`, `unavailable`, `cancelled`, or `failed`. UI clients branch on
|
| 137 |
+
these values rather than message text. Native diagnostic payloads stay private.
|
| 138 |
+
|
| 139 |
+
## Managed model provider requirements
|
| 140 |
+
|
| 141 |
+
Existing threads retain their provider configuration. Input RPCs reject requests when managed
|
| 142 |
+
`model_provider` or `model_providers` requirements no longer match that configuration, or cannot
|
| 143 |
+
be loaded. This covers turn start/steer, review, compaction, manual queue start, and active goal
|
| 144 |
+
updates. Realtime connections use separate routing configuration and are not checked here.
|
| 145 |
+
Interrupt, realtime stop, and goal pause/clear remain available. User and project
|
| 146 |
+
configuration changes alone do not invalidate existing threads.
|
| 147 |
+
|
| 148 |
+
# Amazon Bedrock authentication
|
| 149 |
+
|
| 150 |
+
If `model_providers.amazon-bedrock.aws.credential_export` is configured, Bedrock setup and
|
| 151 |
+
Bedrock login return an error without changing configuration or saved credentials. Remove the
|
| 152 |
+
exporter configuration before selecting another credential source. `aws.credential_export` and
|
| 153 |
+
`aws.profile` cannot be configured together.
|
| 154 |
+
|
| 155 |
+
## Stored thread attachments
|
| 156 |
+
|
| 157 |
+
- `thread/attachment/add` — add a durable resource reference to a stored thread without loading it. Repeated writes with the same attachment type and identity key return the existing attachment.
|
| 158 |
+
- `thread/attachment/list` — list attachments for one stored thread in a cursor-paginated request, including a thread that is not loaded.
|
| 159 |
+
- `thread/attachment/remove` — remove an attachment by its thread, attachment type, and identity key; returns `{}`.
|
| 160 |
+
- `thread/attachment/updated` — notification broadcast after an attachment is created or removed; contains the thread, attachment identity, attachment id, and operation.
|
| 161 |
+
### Example: Manage stored thread attachments
|
| 162 |
+
|
| 163 |
+
Attachments record the resources currently associated with a thread, independently of conversation history. Clients can add, remove, and list attachments for one stored thread at a time without resuming those threads. Adding or removing an attachment does not create or delete the underlying resource or rewrite history. An attachment is idempotently identified by its thread, `attachmentType`, and `identityKey`. For pull requests, clients should reuse the canonical application identity `JSON.stringify([canonicalHostname, lowercaseOwner, lowercaseRepository, pullRequestNumber])` so addition and removal agree across surfaces.
|
| 164 |
+
|
| 165 |
+
```json
|
| 166 |
+
{ "method": "thread/attachment/add", "id": 20, "params": {
|
| 167 |
+
"threadId": "thr_123",
|
| 168 |
+
"attachmentType": "pull_request",
|
| 169 |
+
"identityKey": "[\"github.com\",\"openai\",\"codex\",123]",
|
| 170 |
+
"payload": { "url": "https://github.com/openai/codex/pull/123" }
|
| 171 |
+
} }
|
| 172 |
+
{ "id": 20, "result": {
|
| 173 |
+
"outcome": "created",
|
| 174 |
+
"attachment": {
|
| 175 |
+
"id": "01984de2-8f74-7c91-a3b2-5c5e937cf318",
|
| 176 |
+
"attachmentType": "pull_request",
|
| 177 |
+
"identityKey": "[\"github.com\",\"openai\",\"codex\",123]",
|
| 178 |
+
"payload": { "url": "https://github.com/openai/codex/pull/123" },
|
| 179 |
+
"createdAt": 1750000000
|
| 180 |
+
}
|
| 181 |
+
} }
|
| 182 |
+
|
| 183 |
+
{ "method": "thread/attachment/list", "id": 21, "params": {
|
| 184 |
+
"threadId": "thr_123",
|
| 185 |
+
"limit": 100
|
| 186 |
+
} }
|
| 187 |
+
{ "id": 21, "result": {
|
| 188 |
+
"data": [{
|
| 189 |
+
"id": "01984de2-8f74-7c91-a3b2-5c5e937cf318",
|
| 190 |
+
"attachmentType": "pull_request",
|
| 191 |
+
"identityKey": "[\"github.com\",\"openai\",\"codex\",123]",
|
| 192 |
+
"payload": { "url": "https://github.com/openai/codex/pull/123" },
|
| 193 |
+
"createdAt": 1750000000
|
| 194 |
+
}],
|
| 195 |
+
"nextCursor": null
|
| 196 |
+
} }
|
| 197 |
+
|
| 198 |
+
{ "method": "thread/attachment/remove", "id": 22, "params": {
|
| 199 |
+
"threadId": "thr_123",
|
| 200 |
+
"attachmentType": "pull_request",
|
| 201 |
+
"identityKey": "[\"github.com\",\"openai\",\"codex\",123]"
|
| 202 |
+
} }
|
| 203 |
+
{ "id": 22, "result": {} }
|
| 204 |
+
|
| 205 |
+
{ "method": "thread/attachment/updated", "params": {
|
| 206 |
+
"threadId": "thr_123",
|
| 207 |
+
"attachmentType": "pull_request",
|
| 208 |
+
"identityKey": "[\"github.com\",\"openai\",\"codex\",123]",
|
| 209 |
+
"attachmentId": "01984de2-8f74-7c91-a3b2-5c5e937cf318",
|
| 210 |
+
"operation": "deleted"
|
| 211 |
+
} }
|
| 212 |
+
```
|
| 213 |
+
|
| 214 |
+
`thread/attachment/list` accepts one `threadId` and returns at most 100 attachments per page, ordered by creation time and attachment id. Continue with `nextCursor` and the same `threadId` until the cursor is `null`. Each thread can retain up to 100 attachments. Removing an attachment frees a slot for a new attachment.
|
| 215 |
+
|
| 216 |
+
A non-ephemeral fork copies the source thread's current attachments, even when forking at an earlier turn. The copies have new attachment IDs and creation timestamps, but retain the same resource identities and payloads. Clients use `forkedFromId` on `thread/started` to detect forks and call `thread/attachment/list` with the new thread ID to load their attachments. Fork copying does not emit per-attachment updates; explicit add/remove operations still do. Copying is awaited before publishing the fork, but is best effort: a copy failure is logged and the conversation fork succeeds without attachments. Membership can then change independently on either thread; the referenced resources themselves are not copied. Resuming a fork does not repeat the copy.
|
| 217 |
+
|
| 218 |
+
Attachment creation and deletion requests using the same thread ID are serialized across connections. The requesting client receives its response before the compact update is broadcast, and duplicate creates or absent deletes do not emit updates. Deleting the owning thread removes its attachments under the same lifecycle exclusion; queued attachment mutations then report that the thread was not found.
|
| 219 |
+
|
| 220 |
+
# Thread plugin settings
|
| 221 |
+
|
| 222 |
+
`thread/settings/update` and `turn/start` accept `disabledPluginIds`, a list of
|
| 223 |
+
`PluginSummary.id` values from `plugin/list`, in the
|
| 224 |
+
`<plugin-name>@<marketplace-name>` format. A supplied list replaces the selection;
|
| 225 |
+
omission or `null` preserves it, and `[]` clears it. Saving this selection does
|
| 226 |
+
not yet filter plugin capabilities.
|
| 227 |
+
|
| 228 |
+
Read the selection from `threadSettings.disabledPluginIds` in
|
| 229 |
+
`thread/settings/updated` notifications, or from `disabledPluginIds` in
|
| 230 |
+
`thread/start`, `thread/resume`, and `thread/fork` responses. Selections persist
|
| 231 |
+
across resume. Forks restore the selection from the history retained at the
|
| 232 |
+
requested fork boundary.
|
| 233 |
+
|
| 234 |
+
# Deprecated thread personality setting
|
| 235 |
+
|
| 236 |
+
`thread/start`, `thread/resume`, `thread/settings/update`, and `turn/start` still
|
| 237 |
+
accept `personality`, but `friendly` and `pragmatic` no longer select a style.
|
| 238 |
+
`model/list` returns `supportsPersonality: false` for every model.
|
| 239 |
+
|
| 240 |
+
`none` removes the literal `# Personality` section when Codex prepares
|
| 241 |
+
instructions from the model catalog, for example when starting a thread or
|
| 242 |
+
switching models. Setting `friendly` or `pragmatic` can replace a previous
|
| 243 |
+
`none` setting for that purpose. Changing the setting does not rewrite the
|
| 244 |
+
thread's existing instructions or change explicitly supplied base instructions.
|
| 245 |
+
The old `features.personality` flag is ignored.
|
| 246 |
+
|
| 247 |
+
# MCP server capabilities
|
| 248 |
+
|
| 249 |
+
`mcpServerStatus/list` returns `serverCapabilities` for each initialized MCP server
|
| 250 |
+
in both `full` and `toolsAndAuthOnly` detail modes, including thread-scoped reads.
|
| 251 |
+
This is the server's advertised MCP capabilities object, including its `extensions`
|
| 252 |
+
map. It is null when the connection has not initialized successfully; capabilities
|
| 253 |
+
are never inferred from tools or copied from a shared catalog cache.
|
| 254 |
+
|
| 255 |
+
# Thread rollback
|
| 256 |
+
|
| 257 |
+
`thread/rollback` has been removed from the API, including its request and response
|
| 258 |
+
types. Requests use the generic unknown-method rejection path. Use `thread/revert`
|
| 259 |
+
for paginated threads instead.
|
| 260 |
+
|
| 261 |
+
Existing rollouts may contain historical `ThreadRolledBack` events. Their replay
|
| 262 |
+
and migration remain supported so resuming, reading, and forking those threads
|
| 263 |
+
preserves the surviving history. This disk compatibility does not require restoring
|
| 264 |
+
support for new `thread/rollback` requests.
|
| 265 |
+
|
| 266 |
+
# Selected workspace routing
|
| 267 |
+
|
| 268 |
+
The experimental `account/read.workspaceRouting` response field returns the selected ChatGPT workspace's `chatgptAccountId`, resolved HTTPS `backendOrigin`, and backend-provided `accountRoutingOverride`. The routing value is `us`, `us_cr`, or the explicit `NO_CONSTRAINT` value. API-only and signed-out accounts return `null` and do not need `accounts/check`.
|
| 269 |
+
|
| 270 |
+
App-server discovers routing for saved ChatGPT logins at startup and for new logins or workspace switches. After requirements and routing are ready, it sends the existing `account/updated` notification. Newly initialized connections also receive this notification once saved-workspace routing is ready, including when discovery finished before the connection initialized. Clients then reread `configRequirements/read` and `account/read`. Saved ChatGPT credentials without a selected workspace ID retain their account information and return `workspaceRouting: null`; app-server does not guess a workspace from the backend's default account. Discovery failures for a selected workspace, including missing or null fields from older backends, return an `account/read` error. They never produce a successful unrestricted result. A later read retries failed discovery. Logout clears the cached routing, and results from earlier authentication owners are discarded. Token refreshes for the same known user and workspace invalidate cached routing without cancelling discovery or failing sign-in. Configuration is reloaded after discovery; a changed backend, model provider, or required backend rejects the result so the next read discovers against current configuration. Account notifications recheck the auth owner generation after waiting for outbound queue capacity. Superseded sign-in attempts emit a failed `account/login/completed` event instead of silently dropping completion. Notifications remain snapshots: clients reread current account and requirements state rather than treating a queued notification as authorization.
|
| 271 |
+
|
| 272 |
+
The origin of a required `chatgpt_base_url` must match the discovered origin by scheme, host, and effective port. The base URL's API path is not part of this comparison. Either origin alone is sufficient. If requirements specify no base URL and discovery explicitly returns `NO_CONSTRAINT`, the effective `chatgpt_base_url` supplies the origin, including its existing default. `backendOrigin` is always a resolved origin; `accountRoutingOverride` preserves `NO_CONSTRAINT` when the backend explicitly returns it. Discovering an origin does not change API paths or apply routing headers to requests.
|
| 273 |
+
|
| 274 |
+
## Windows sandbox implementation selection
|
| 275 |
+
|
| 276 |
+
`windowsSandbox/setupStart` and `windowsSandbox/readiness` apply only to the
|
| 277 |
+
legacy `elevated` and `unelevated` backends. Clients resolve the desired sandbox
|
| 278 |
+
implementation from configuration. When it is `mxc`, they skip both methods;
|
| 279 |
+
`allowedWindowsSandboxImplementations` can allow `mxc` independently of the
|
| 280 |
+
legacy setup modes. Non-Windows hosts report `notConfigured` for the legacy
|
| 281 |
+
readiness API.
|
| 282 |
+
|
| 283 |
+
MXC uses the standard `command/exec` streaming and process-control path, including
|
| 284 |
+
ConPTY when `tty` is enabled. The buffered legacy Windows sandbox restrictions on
|
| 285 |
+
process control and custom output caps do not apply to MXC.
|
codex-rs/apply-patch/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "apply-patch",
|
| 5 |
+
crate_name = "codex_apply_patch",
|
| 6 |
+
)
|
codex-rs/apply-patch/Cargo.toml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-apply-patch"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_apply_patch"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[[bin]]
|
| 13 |
+
name = "apply_patch"
|
| 14 |
+
path = "src/main.rs"
|
| 15 |
+
|
| 16 |
+
[lints]
|
| 17 |
+
workspace = true
|
| 18 |
+
|
| 19 |
+
[dependencies]
|
| 20 |
+
anyhow = { workspace = true }
|
| 21 |
+
codex-exec-server = { workspace = true }
|
| 22 |
+
codex-utils-absolute-path = { workspace = true }
|
| 23 |
+
codex-utils-path-uri = { workspace = true }
|
| 24 |
+
similar = { workspace = true }
|
| 25 |
+
thiserror = { workspace = true }
|
| 26 |
+
tokio = { workspace = true, features = ["macros", "rt"] }
|
| 27 |
+
tree-sitter = { workspace = true }
|
| 28 |
+
tree-sitter-bash = { workspace = true }
|
| 29 |
+
|
| 30 |
+
[dev-dependencies]
|
| 31 |
+
assert_cmd = { workspace = true }
|
| 32 |
+
assert_matches = { workspace = true }
|
| 33 |
+
codex-utils-cargo-bin = { workspace = true }
|
| 34 |
+
pretty_assertions = { workspace = true }
|
| 35 |
+
tempfile = { workspace = true }
|
codex-rs/arg0/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "arg0",
|
| 5 |
+
crate_name = "codex_arg0",
|
| 6 |
+
)
|
codex-rs/arg0/Cargo.toml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-arg0"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_arg0"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
anyhow = { workspace = true }
|
| 17 |
+
codex-apply-patch = { workspace = true }
|
| 18 |
+
codex-async-utils = { workspace = true }
|
| 19 |
+
codex-exec-server = { workspace = true }
|
| 20 |
+
codex-install-context = { workspace = true }
|
| 21 |
+
codex-linux-sandbox = { workspace = true }
|
| 22 |
+
codex-sandboxing = { workspace = true }
|
| 23 |
+
codex-shell-escalation = { workspace = true }
|
| 24 |
+
codex-utils-absolute-path = { workspace = true }
|
| 25 |
+
codex-utils-home-dir = { workspace = true }
|
| 26 |
+
dotenvy = { workspace = true }
|
| 27 |
+
tempfile = { workspace = true }
|
| 28 |
+
tokio = { workspace = true, features = ["rt-multi-thread"] }
|
| 29 |
+
|
| 30 |
+
[target.'cfg(windows)'.dependencies]
|
| 31 |
+
codex-windows-sandbox = { workspace = true }
|
| 32 |
+
pathdiff = { workspace = true }
|
| 33 |
+
|
| 34 |
+
[dev-dependencies]
|
| 35 |
+
pretty_assertions = { workspace = true }
|
codex-rs/async-utils/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "async-utils",
|
| 5 |
+
crate_name = "codex_async_utils",
|
| 6 |
+
)
|
codex-rs/async-utils/Cargo.toml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-async-utils"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lints]
|
| 8 |
+
workspace = true
|
| 9 |
+
|
| 10 |
+
[dependencies]
|
| 11 |
+
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "time"] }
|
| 12 |
+
tokio-util.workspace = true
|
| 13 |
+
|
| 14 |
+
[dev-dependencies]
|
| 15 |
+
pretty_assertions.workspace = true
|
| 16 |
+
|
| 17 |
+
[lib]
|
| 18 |
+
doctest = false
|
codex-rs/attachment-store/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "attachment-store",
|
| 5 |
+
crate_name = "codex_attachment_store",
|
| 6 |
+
)
|
codex-rs/attachment-store/Cargo.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-attachment-store"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
doctest = false
|
| 9 |
+
name = "codex_attachment_store"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
serde = { workspace = true, features = ["derive"] }
|
| 17 |
+
|
| 18 |
+
[dev-dependencies]
|
| 19 |
+
pretty_assertions = { workspace = true }
|
| 20 |
+
tokio = { workspace = true, features = ["macros", "rt", "sync"] }
|
codex-rs/aws-auth/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "aws-auth",
|
| 5 |
+
crate_name = "codex_aws_auth",
|
| 6 |
+
)
|
codex-rs/aws-auth/Cargo.toml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-aws-auth"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
doctest = false
|
| 9 |
+
name = "codex_aws_auth"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
aws-config = { workspace = true, features = ["credentials-login"] }
|
| 17 |
+
aws-credential-types = { workspace = true }
|
| 18 |
+
aws-sigv4 = { workspace = true }
|
| 19 |
+
aws-types = { workspace = true }
|
| 20 |
+
bytes = { workspace = true }
|
| 21 |
+
http = { workspace = true }
|
| 22 |
+
thiserror = { workspace = true }
|
| 23 |
+
|
| 24 |
+
[dev-dependencies]
|
| 25 |
+
pretty_assertions = { workspace = true }
|
| 26 |
+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
codex-rs/backend-client/BUILD.bazel
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "backend-client",
|
| 5 |
+
compile_data = glob(["tests/fixtures/**"]),
|
| 6 |
+
crate_name = "codex_backend_client",
|
| 7 |
+
)
|
codex-rs/backend-client/Cargo.toml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-backend-client"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
publish = false
|
| 7 |
+
|
| 8 |
+
[lib]
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
doctest = false
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
anyhow = "1"
|
| 17 |
+
serde = { version = "1", features = ["derive"] }
|
| 18 |
+
serde_json = "1"
|
| 19 |
+
http = { workspace = true }
|
| 20 |
+
url = { workspace = true }
|
| 21 |
+
codex-backend-openapi-models = { path = "../codex-backend-openapi-models" }
|
| 22 |
+
codex-api = { workspace = true }
|
| 23 |
+
codex-http-client = { workspace = true }
|
| 24 |
+
codex-login = { workspace = true }
|
| 25 |
+
codex-model-provider = { workspace = true }
|
| 26 |
+
codex-protocol = { workspace = true }
|
| 27 |
+
|
| 28 |
+
[dev-dependencies]
|
| 29 |
+
pretty_assertions = "1"
|
| 30 |
+
tokio = { workspace = true, features = ["macros", "rt"] }
|
| 31 |
+
wiremock = { workspace = true }
|
codex-rs/build-info/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "build-info",
|
| 5 |
+
crate_name = "codex_build_info",
|
| 6 |
+
)
|
codex-rs/build-info/Cargo.toml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-build-info"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
doctest = false
|
| 9 |
+
name = "codex_build_info"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
|
| 12 |
+
[lints]
|
| 13 |
+
workspace = true
|
| 14 |
+
|
| 15 |
+
[dependencies]
|
| 16 |
+
codex-install-context = { workspace = true }
|
| 17 |
+
semver = { workspace = true, features = ["serde"] }
|
| 18 |
+
serde = { workspace = true, features = ["derive"] }
|
| 19 |
+
sha2 = { workspace = true }
|
| 20 |
+
|
| 21 |
+
[dev-dependencies]
|
| 22 |
+
pretty_assertions = { workspace = true }
|
| 23 |
+
serde_json = { workspace = true }
|
| 24 |
+
tempfile = { workspace = true }
|
codex-rs/build-info/build.rs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//! Embed the compilation target, including its architecture and ABI.
|
| 2 |
+
|
| 3 |
+
fn main() -> Result<(), std::env::VarError> {
|
| 4 |
+
let target = std::env::var("TARGET")?;
|
| 5 |
+
println!("cargo:rustc-env=CODEX_BUILD_TARGET={target}");
|
| 6 |
+
println!("cargo:rerun-if-changed=build.rs");
|
| 7 |
+
Ok(())
|
| 8 |
+
}
|
codex-rs/chatgpt/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "chatgpt",
|
| 5 |
+
crate_name = "codex_chatgpt",
|
| 6 |
+
)
|
codex-rs/chatgpt/Cargo.toml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-chatgpt"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
|
| 7 |
+
[lints]
|
| 8 |
+
workspace = true
|
| 9 |
+
|
| 10 |
+
[dependencies]
|
| 11 |
+
anyhow = { workspace = true }
|
| 12 |
+
clap = { workspace = true, features = ["derive"] }
|
| 13 |
+
codex-connectors = { workspace = true }
|
| 14 |
+
codex-core = { workspace = true }
|
| 15 |
+
codex-git-utils = { workspace = true }
|
| 16 |
+
codex-http-client = { workspace = true }
|
| 17 |
+
codex-login = { workspace = true }
|
| 18 |
+
codex-model-provider = { workspace = true }
|
| 19 |
+
codex-plugin = { workspace = true }
|
| 20 |
+
codex-utils-cli = { workspace = true }
|
| 21 |
+
serde = { workspace = true, features = ["derive"] }
|
| 22 |
+
tokio = { workspace = true, features = ["full"] }
|
| 23 |
+
|
| 24 |
+
[dev-dependencies]
|
| 25 |
+
codex-utils-cargo-bin = { workspace = true }
|
| 26 |
+
pretty_assertions = { workspace = true }
|
| 27 |
+
serde_json = { workspace = true }
|
| 28 |
+
tempfile = { workspace = true }
|
| 29 |
+
|
| 30 |
+
[lib]
|
| 31 |
+
doctest = false
|
codex-rs/chatgpt/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ChatGPT
|
| 2 |
+
|
| 3 |
+
This crate pertains to first party ChatGPT APIs and products such as Codex agent.
|
| 4 |
+
|
| 5 |
+
This crate is built and maintained by OpenAI employees. External code contributions are not accepted; please report bugs and request features in the [Codex issue tracker](https://github.com/openai/codex/issues).
|
codex-rs/cli/BUILD.bazel
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate")
|
| 2 |
+
load("//bazel/platforms:release_binaries.bzl", "multiplatform_binaries")
|
| 3 |
+
load("//bazel/rules:e2e_benchmark.bzl", "codex_e2e_benchmark")
|
| 4 |
+
|
| 5 |
+
codex_rust_crate(
|
| 6 |
+
name = "cli",
|
| 7 |
+
binaries_with_build_commit = ["codex"],
|
| 8 |
+
crate_name = "codex_cli",
|
| 9 |
+
extra_binaries = [
|
| 10 |
+
"//codex-rs/bwrap:bwrap",
|
| 11 |
+
],
|
| 12 |
+
rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS,
|
| 13 |
+
test_data_extra = glob(["src/**/snapshots/**"]),
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
multiplatform_binaries(
|
| 17 |
+
name = "codex",
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
codex_e2e_benchmark(
|
| 21 |
+
name = "codex-help",
|
| 22 |
+
binaries = [":codex"],
|
| 23 |
+
)
|
codex-rs/cli/Cargo.toml
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "codex-cli"
|
| 3 |
+
version.workspace = true
|
| 4 |
+
edition.workspace = true
|
| 5 |
+
license.workspace = true
|
| 6 |
+
build = "build.rs"
|
| 7 |
+
default-run = "codex"
|
| 8 |
+
|
| 9 |
+
[[bin]]
|
| 10 |
+
name = "codex"
|
| 11 |
+
path = "src/main.rs"
|
| 12 |
+
|
| 13 |
+
[[bin]]
|
| 14 |
+
name = "logs_client"
|
| 15 |
+
path = "src/bin/logs_client.rs"
|
| 16 |
+
|
| 17 |
+
[lib]
|
| 18 |
+
name = "codex_cli"
|
| 19 |
+
path = "src/lib.rs"
|
| 20 |
+
doctest = false
|
| 21 |
+
|
| 22 |
+
[lints]
|
| 23 |
+
workspace = true
|
| 24 |
+
|
| 25 |
+
[dependencies]
|
| 26 |
+
anyhow = { workspace = true }
|
| 27 |
+
chrono = { workspace = true }
|
| 28 |
+
clap = { workspace = true, features = ["derive", "env"] }
|
| 29 |
+
clap_complete = { workspace = true }
|
| 30 |
+
codex-app-server = { workspace = true }
|
| 31 |
+
codex-app-server-daemon = { workspace = true }
|
| 32 |
+
codex-app-server-protocol = { workspace = true }
|
| 33 |
+
codex-app-server-test-client = { workspace = true }
|
| 34 |
+
codex-arg0 = { workspace = true }
|
| 35 |
+
codex-build-info = { workspace = true }
|
| 36 |
+
codex-api = { workspace = true }
|
| 37 |
+
codex-aws-auth = { workspace = true }
|
| 38 |
+
codex-chatgpt = { workspace = true }
|
| 39 |
+
codex-cloud-config = { workspace = true }
|
| 40 |
+
codex-cloud-tasks = { path = "../cloud-tasks" }
|
| 41 |
+
codex-utils-cli = { workspace = true }
|
| 42 |
+
codex-config = { workspace = true }
|
| 43 |
+
codex-core = { workspace = true }
|
| 44 |
+
codex-core-plugins = { workspace = true }
|
| 45 |
+
codex-history = { workspace = true }
|
| 46 |
+
codex-home = { workspace = true }
|
| 47 |
+
codex-http-client = { workspace = true }
|
| 48 |
+
codex-exec = { workspace = true }
|
| 49 |
+
codex-exec-server = { workspace = true }
|
| 50 |
+
codex-execpolicy = { workspace = true }
|
| 51 |
+
codex-extension-api = { workspace = true }
|
| 52 |
+
codex-features = { workspace = true }
|
| 53 |
+
codex-git-attribution = { workspace = true }
|
| 54 |
+
codex-git-utils = { workspace = true }
|
| 55 |
+
codex-install-context = { workspace = true }
|
| 56 |
+
codex-login = { workspace = true }
|
| 57 |
+
codex-memories-write = { workspace = true }
|
| 58 |
+
codex-mcp = { workspace = true }
|
| 59 |
+
codex-model-provider = { workspace = true }
|
| 60 |
+
codex-models-manager = { workspace = true }
|
| 61 |
+
codex-plugin = { workspace = true }
|
| 62 |
+
codex-protocol = { workspace = true }
|
| 63 |
+
codex-responses-api-proxy = { workspace = true }
|
| 64 |
+
codex-tcp-tunnel = { workspace = true }
|
| 65 |
+
codex-rmcp-client = { workspace = true }
|
| 66 |
+
codex-rollout = { workspace = true }
|
| 67 |
+
codex-rollout-trace = { workspace = true }
|
| 68 |
+
codex-sandboxing = { workspace = true }
|
| 69 |
+
codex-skills-extension = { workspace = true }
|
| 70 |
+
codex-state = { workspace = true }
|
| 71 |
+
codex-stdio-to-uds = { workspace = true }
|
| 72 |
+
codex-terminal-detection = { workspace = true }
|
| 73 |
+
codex-thread-store = { workspace = true }
|
| 74 |
+
codex-tui = { workspace = true }
|
| 75 |
+
codex-utils-absolute-path = { workspace = true }
|
| 76 |
+
codex-utils-path = { workspace = true }
|
| 77 |
+
codex-utils-path-uri = { workspace = true }
|
| 78 |
+
crossterm = { workspace = true, features = ["event-stream"] }
|
| 79 |
+
futures = { workspace = true }
|
| 80 |
+
http = { workspace = true }
|
| 81 |
+
libc = { workspace = true }
|
| 82 |
+
os_info = { workspace = true }
|
| 83 |
+
owo-colors = { workspace = true }
|
| 84 |
+
regex-lite = { workspace = true }
|
| 85 |
+
serde = { workspace = true, features = ["derive"] }
|
| 86 |
+
serde_json = { workspace = true }
|
| 87 |
+
supports-color = { workspace = true }
|
| 88 |
+
sys-locale = { workspace = true }
|
| 89 |
+
tempfile = { workspace = true }
|
| 90 |
+
tokio = { workspace = true, features = [
|
| 91 |
+
"io-std",
|
| 92 |
+
"macros",
|
| 93 |
+
"net",
|
| 94 |
+
"process",
|
| 95 |
+
"rt-multi-thread",
|
| 96 |
+
"signal",
|
| 97 |
+
"time",
|
| 98 |
+
] }
|
| 99 |
+
toml = { workspace = true }
|
| 100 |
+
tracing = { workspace = true }
|
| 101 |
+
tracing-appender = { workspace = true }
|
| 102 |
+
tracing-subscriber = { workspace = true }
|
| 103 |
+
unicode-segmentation = { workspace = true }
|
| 104 |
+
url = { workspace = true }
|
| 105 |
+
which = { workspace = true }
|
| 106 |
+
|
| 107 |
+
[target.'cfg(all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
|
| 108 |
+
tikv-jemallocator = { workspace = true }
|
| 109 |
+
|
| 110 |
+
[target.'cfg(target_os = "windows")'.dependencies]
|
| 111 |
+
codex_windows_sandbox = { package = "codex-windows-sandbox", path = "../windows-sandbox-rs" }
|
| 112 |
+
windows-sys = { version = "0.52", features = [
|
| 113 |
+
"Win32_Foundation",
|
| 114 |
+
"Win32_Storage_Packaging_Appx",
|
| 115 |
+
"Win32_System_Console",
|
| 116 |
+
"Win32_System_Threading",
|
| 117 |
+
] }
|
| 118 |
+
|
| 119 |
+
[dev-dependencies]
|
| 120 |
+
app_test_support = { workspace = true }
|
| 121 |
+
assert_cmd = { workspace = true }
|
| 122 |
+
assert_matches = { workspace = true }
|
| 123 |
+
codex-utils-cargo-bin = { workspace = true }
|
| 124 |
+
codex-utils-pty = { workspace = true }
|
| 125 |
+
flate2 = { workspace = true }
|
| 126 |
+
insta = { workspace = true }
|
| 127 |
+
predicates = { workspace = true }
|
| 128 |
+
pretty_assertions = { workspace = true }
|
| 129 |
+
sqlx = { workspace = true }
|
| 130 |
+
tar = { workspace = true }
|
| 131 |
+
tokio-tungstenite = { workspace = true }
|
| 132 |
+
wiremock = { workspace = true }
|
| 133 |
+
zstd = { workspace = true }
|
| 134 |
+
|
| 135 |
+
[package.metadata.cargo-shear]
|
| 136 |
+
# These Rust sources are intentionally Bazel-only macrobenchmarks rather than
|
| 137 |
+
# Cargo targets.
|
| 138 |
+
ignored-paths = ["e2e_benches/*.rs"]
|
codex-rs/cli/build.rs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fn main() {
|
| 2 |
+
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos") {
|
| 3 |
+
println!("cargo:rustc-link-arg=-ObjC");
|
| 4 |
+
}
|
| 5 |
+
}
|
codex-rs/cloud-tasks-client/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "cloud-tasks-client",
|
| 5 |
+
crate_name = "codex_cloud_tasks_client",
|
| 6 |
+
)
|
codex-rs/cloud-tasks-client/Cargo.toml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
edition.workspace = true
|
| 3 |
+
license.workspace = true
|
| 4 |
+
name = "codex-cloud-tasks-client"
|
| 5 |
+
version.workspace = true
|
| 6 |
+
|
| 7 |
+
[lib]
|
| 8 |
+
name = "codex_cloud_tasks_client"
|
| 9 |
+
path = "src/lib.rs"
|
| 10 |
+
test = false
|
| 11 |
+
doctest = false
|
| 12 |
+
|
| 13 |
+
[lints]
|
| 14 |
+
workspace = true
|
| 15 |
+
|
| 16 |
+
[dependencies]
|
| 17 |
+
anyhow = { workspace = true }
|
| 18 |
+
chrono = { workspace = true, features = ["serde"] }
|
| 19 |
+
codex-api = { workspace = true }
|
| 20 |
+
codex-backend-client = { workspace = true }
|
| 21 |
+
codex-git-utils = { workspace = true }
|
| 22 |
+
codex-http-client = { workspace = true }
|
| 23 |
+
serde = { version = "1", features = ["derive"] }
|
| 24 |
+
serde_json = { workspace = true }
|
| 25 |
+
thiserror = { workspace = true }
|
codex-rs/cloud-tasks-mock-client/BUILD.bazel
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "cloud-tasks-mock-client",
|
| 5 |
+
crate_name = "codex_cloud_tasks_mock_client",
|
| 6 |
+
)
|
codex-rs/cloud-tasks-mock-client/Cargo.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
[package]
|
| 3 |
+
edition.workspace = true
|
| 4 |
+
license.workspace = true
|
| 5 |
+
name = "codex-cloud-tasks-mock-client"
|
| 6 |
+
version.workspace = true
|
| 7 |
+
|
| 8 |
+
[lib]
|
| 9 |
+
name = "codex_cloud_tasks_mock_client"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
test = false
|
| 12 |
+
doctest = false
|
| 13 |
+
|
| 14 |
+
[lints]
|
| 15 |
+
workspace = true
|
| 16 |
+
|
| 17 |
+
[dependencies]
|
| 18 |
+
chrono = { workspace = true }
|
| 19 |
+
codex-cloud-tasks-client = { workspace = true }
|
| 20 |
+
diffy = { workspace = true }
|
codex-rs/cloud-tasks/BUILD.bazel
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate")
|
| 2 |
+
|
| 3 |
+
codex_rust_crate(
|
| 4 |
+
name = "cloud-tasks",
|
| 5 |
+
crate_name = "codex_cloud_tasks",
|
| 6 |
+
rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS,
|
| 7 |
+
)
|