mirror of
https://github.com/openai/codex.git
synced 2026-04-24 06:35:50 +00:00
Remove legacy Android codexd path
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,6 @@
|
||||
//! targets. Keeping that setup local avoids pulling the TUI's session-oriented logging machinery
|
||||
//! into a one-shot CLI command while still producing a durable `codex-login.log` artifact that
|
||||
//! support can request from users.
|
||||
|
||||
use codex_core::CodexAuth;
|
||||
use codex_core::auth::AuthCredentialsStoreMode;
|
||||
use codex_core::auth::AuthMode;
|
||||
@@ -35,7 +34,6 @@ const CHATGPT_LOGIN_DISABLED_MESSAGE: &str =
|
||||
const API_KEY_LOGIN_DISABLED_MESSAGE: &str =
|
||||
"API key login is disabled. Use ChatGPT login instead.";
|
||||
const LOGIN_SUCCESS_MESSAGE: &str = "Successfully logged in";
|
||||
|
||||
/// Installs a small file-backed tracing layer for direct `codex login` flows.
|
||||
///
|
||||
/// This deliberately duplicates a narrow slice of the TUI logging setup instead of reusing it
|
||||
|
||||
@@ -577,8 +577,8 @@ mod tests {
|
||||
#[test]
|
||||
fn parse_socket_endpoint_preserves_filesystem_paths() {
|
||||
assert_eq!(
|
||||
parse_socket_endpoint(Path::new("/tmp/codexd.sock")).expect("socket endpoint"),
|
||||
UnixSocketEndpoint::Filesystem(PathBuf::from("/tmp/codexd.sock")),
|
||||
parse_socket_endpoint(Path::new("/tmp/openai.sock")).expect("socket endpoint"),
|
||||
UnixSocketEndpoint::Filesystem(PathBuf::from("/tmp/openai.sock")),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ use crate::auth::UnauthorizedRecovery;
|
||||
use crate::auth_env_telemetry::AuthEnvTelemetry;
|
||||
use crate::auth_env_telemetry::collect_auth_env_telemetry;
|
||||
use crate::http_transport::build_api_transport;
|
||||
use crate::openai_socket::should_route_via_openai_socket_proxy;
|
||||
use codex_api::CompactClient as ApiCompactClient;
|
||||
use codex_api::CompactionInput as ApiCompactionInput;
|
||||
use codex_api::MemoriesClient as ApiMemoriesClient;
|
||||
@@ -511,7 +512,8 @@ impl ModelClient {
|
||||
///
|
||||
/// WebSocket use is controlled by provider capability and session-scoped fallback state.
|
||||
pub fn responses_websocket_enabled(&self) -> bool {
|
||||
if !self.state.provider.supports_websockets
|
||||
if should_route_via_openai_socket_proxy()
|
||||
|| !self.state.provider.supports_websockets
|
||||
|| self.state.disable_websockets.load(Ordering::Relaxed)
|
||||
|| (*CODEX_RS_SSE_FIXTURE).is_some()
|
||||
{
|
||||
@@ -526,9 +528,13 @@ impl ModelClient {
|
||||
/// This centralizes setup used by both prewarm and normal request paths so they stay in
|
||||
/// lockstep when auth/provider resolution changes.
|
||||
async fn current_client_setup(&self) -> Result<CurrentClientSetup> {
|
||||
let auth = match self.state.auth_manager.as_ref() {
|
||||
Some(manager) => manager.auth().await,
|
||||
None => None,
|
||||
let auth = if should_route_via_openai_socket_proxy() {
|
||||
None
|
||||
} else {
|
||||
match self.state.auth_manager.as_ref() {
|
||||
Some(manager) => manager.auth().await,
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
let api_provider = self
|
||||
.state
|
||||
|
||||
@@ -83,6 +83,7 @@ use crate::config::types::McpServerConfig;
|
||||
use crate::config::types::McpServerTransportConfig;
|
||||
use crate::connectors::is_connector_id_allowed;
|
||||
use crate::connectors::sanitize_name;
|
||||
use crate::openai_socket::should_route_via_openai_socket_proxy;
|
||||
|
||||
/// Delimiter used to separate the server name from the tool name in a fully
|
||||
/// qualified tool name.
|
||||
@@ -1455,6 +1456,11 @@ async fn make_rmcp_client(
|
||||
env_http_headers,
|
||||
bearer_token_env_var,
|
||||
} => {
|
||||
if should_route_via_openai_socket_proxy() {
|
||||
return Err(StartupOutcomeError::from(anyhow!(
|
||||
"streamable HTTP MCP servers are disabled when routing through an OpenAI socket proxy"
|
||||
)));
|
||||
}
|
||||
let resolved_bearer_token =
|
||||
match resolve_bearer_token(server_name, bearer_token_env_var.as_deref()) {
|
||||
Ok(token) => token,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::ffi::OsString;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const CODEX_OPENAI_UNIX_SOCKET_ENV_VAR: &str = "CODEX_OPENAI_UNIX_SOCKET";
|
||||
@@ -11,43 +10,11 @@ pub fn openai_unix_socket_path() -> Option<PathBuf> {
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(PathBuf::from)
|
||||
.or_else(default_android_socket_path)
|
||||
}
|
||||
|
||||
pub fn should_route_via_codexd() -> bool {
|
||||
(openai_unix_socket_path().is_some()
|
||||
|| should_use_agent_auth_proxy_env(std::env::var_os(CODEX_USE_AGENT_AUTH_PROXY_ENV_VAR)))
|
||||
&& !is_codexd_process()
|
||||
}
|
||||
|
||||
fn is_codexd_process() -> bool {
|
||||
std::env::args_os()
|
||||
.next()
|
||||
.and_then(|arg0| {
|
||||
Path::new(&arg0)
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.map(str::to_string)
|
||||
})
|
||||
.is_some_and(|arg0| arg0.contains("codexd"))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
fn default_android_socket_path() -> Option<PathBuf> {
|
||||
const CANDIDATES: [&str; 2] = [
|
||||
"/data/data/com.openai.codexd/files/codexd.sock",
|
||||
"/data/user/0/com.openai.codexd/files/codexd.sock",
|
||||
];
|
||||
|
||||
CANDIDATES
|
||||
.iter()
|
||||
.map(PathBuf::from)
|
||||
.find(|path| path.exists())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn default_android_socket_path() -> Option<PathBuf> {
|
||||
None
|
||||
pub fn should_route_via_openai_socket_proxy() -> bool {
|
||||
openai_unix_socket_path().is_some()
|
||||
|| should_use_agent_auth_proxy_env(std::env::var_os(CODEX_USE_AGENT_AUTH_PROXY_ENV_VAR))
|
||||
}
|
||||
|
||||
fn should_use_agent_auth_proxy_env(value: Option<OsString>) -> bool {
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::auth::storage::AuthStorageBackend;
|
||||
use crate::auth::storage::create_auth_storage;
|
||||
use crate::auth::util::try_parse_error_message;
|
||||
use crate::default_client::create_client;
|
||||
use crate::openai_socket::should_route_via_openai_socket_proxy;
|
||||
use crate::token_data::KnownPlan as InternalKnownPlan;
|
||||
use crate::token_data::PlanType as InternalPlanType;
|
||||
use crate::token_data::TokenData;
|
||||
@@ -1127,6 +1128,9 @@ impl AuthManager {
|
||||
/// For stale managed ChatGPT auth, first performs a guarded reload and then
|
||||
/// refreshes only if the on-disk auth is unchanged.
|
||||
pub async fn auth(&self) -> Option<CodexAuth> {
|
||||
if should_route_via_openai_socket_proxy() {
|
||||
return self.auth_cached();
|
||||
}
|
||||
let auth = self.auth_cached()?;
|
||||
if Self::is_stale_for_proactive_refresh(&auth)
|
||||
&& let Err(err) = self.refresh_token().await
|
||||
@@ -1312,6 +1316,10 @@ impl AuthManager {
|
||||
/// can assume that some other instance already refreshed it. If the persisted
|
||||
/// token is the same as the cached, then ask the token authority to refresh.
|
||||
pub async fn refresh_token(&self) -> Result<(), RefreshTokenError> {
|
||||
let _refresh_guard = self.refresh_lock.lock().await;
|
||||
if should_route_via_openai_socket_proxy() {
|
||||
return Ok(());
|
||||
}
|
||||
let _refresh_guard = self.refresh_lock.lock().await;
|
||||
let auth_before_reload = self.auth_cached();
|
||||
if auth_before_reload
|
||||
|
||||
@@ -31,6 +31,7 @@ use codex_core::default_client::set_default_client_residency_requirement;
|
||||
use codex_core::find_thread_path_by_id_str;
|
||||
use codex_core::find_thread_path_by_name_str;
|
||||
use codex_core::format_exec_policy_error_with_source;
|
||||
use codex_core::openai_socket::openai_unix_socket_path;
|
||||
use codex_core::path_utils;
|
||||
use codex_core::read_session_meta_line;
|
||||
use codex_core::state_db::get_state_db;
|
||||
@@ -644,7 +645,7 @@ async fn run_ratatui_app(
|
||||
/*enable_codex_api_key_env*/ false,
|
||||
initial_config.cli_auth_credentials_store_mode,
|
||||
);
|
||||
let login_status = get_login_status(&initial_config);
|
||||
let login_status = get_login_status(&initial_config).await;
|
||||
let should_show_trust_screen_flag = should_show_trust_screen(&initial_config);
|
||||
let should_show_onboarding =
|
||||
should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag);
|
||||
@@ -1215,11 +1216,15 @@ fn determine_alt_screen_mode(no_alt_screen: bool, tui_alternate_screen: AltScree
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LoginStatus {
|
||||
AuthMode(AuthMode),
|
||||
ExternalProxy,
|
||||
NotAuthenticated,
|
||||
}
|
||||
|
||||
fn get_login_status(config: &Config) -> LoginStatus {
|
||||
async fn get_login_status(config: &Config) -> LoginStatus {
|
||||
if config.model_provider.requires_openai_auth {
|
||||
if openai_unix_socket_path().is_some() {
|
||||
return LoginStatus::ExternalProxy;
|
||||
}
|
||||
// Reading the OpenAI API key is an async operation because it may need
|
||||
// to refresh the token. Block on it.
|
||||
let codex_home = config.codex_home.clone();
|
||||
|
||||
@@ -7,6 +7,7 @@ use chrono::Duration;
|
||||
use chrono::Utc;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::openai_socket::should_route_via_openai_socket_proxy;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::path::Path;
|
||||
@@ -15,6 +16,9 @@ use std::path::PathBuf;
|
||||
use crate::version::CODEX_CLI_VERSION;
|
||||
|
||||
pub fn get_upgrade_version(config: &Config) -> Option<String> {
|
||||
if should_route_via_openai_socket_proxy() {
|
||||
return None;
|
||||
}
|
||||
if !config.check_for_update_on_startup {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ The current repo now contains these implementation slices:
|
||||
cross-app bind or raw local sockets.
|
||||
- The session bridge now exposes a **narrow Responses transport** owned by the
|
||||
Agent app itself, so Genie model traffic no longer depends on any separate
|
||||
`codexd` socket service.
|
||||
sidecar socket service.
|
||||
- The Genie runtime now keeps host dynamic tools limited to framework-only
|
||||
detached-target controls and frame capture, while standard Android shell and
|
||||
device commands stay in the normal Codex tool path.
|
||||
@@ -69,9 +69,9 @@ The current repo now contains these implementation slices:
|
||||
`am start --user 0 ...`.
|
||||
|
||||
The Android app now owns auth, runtime status, and Genie Responses forwarding
|
||||
directly through the hosted Agent runtime. The standalone Rust `codexd`
|
||||
service/client split remains only as a legacy compatibility path outside the
|
||||
Agent/Genie APK flow.
|
||||
directly through the hosted Agent runtime. The older standalone
|
||||
service/client split has been removed from the repo and is no longer part of
|
||||
the Android Agent/Genie flow.
|
||||
|
||||
## Fixed Architecture Decisions
|
||||
|
||||
@@ -158,7 +158,7 @@ Agent/Genie APK flow.
|
||||
- Hosted `codex app-server` inside Genie, with model traffic routed through a
|
||||
Genie-local proxy backed by the Agent framework session bridge
|
||||
- Agent-owned `/v1/responses` proxying in
|
||||
`android/app/src/main/java/com/openai/codexd/AgentResponsesProxy.kt`
|
||||
`android/app/src/main/java/com/openai/codex/agent/AgentResponsesProxy.kt`
|
||||
- Framework-only Android dynamic tools registered on the Genie Codex thread with:
|
||||
- detached target show/hide/attach/close
|
||||
- detached frame capture
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- Treat keyring storage as unsupported on Android and use file-backed storage instead.
|
||||
- Add a `just android-build` helper that uses `cargo-ndk` to build `codex` for `arm64-v8a` and `x86_64` (API 26).
|
||||
- Document build and run steps for pushing the binary to a device.
|
||||
- Build the Android Agent/Genie apps directly on `codex`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -32,6 +33,10 @@ For faster local iteration, you can skip Android release LTO:
|
||||
```bash
|
||||
CODEX_ANDROID_SKIP_LTO=1 just android-build
|
||||
```
|
||||
|
||||
The Agent and Genie APKs now package only `codex`, so Android app builds require
|
||||
only `just android-build`.
|
||||
|
||||
Build the Android Agent/Genie prototype APKs with the Android Agent Platform
|
||||
stub SDK:
|
||||
|
||||
@@ -50,6 +55,7 @@ The Agent/Genie prototype modules also require
|
||||
Gradle can compile against the stub SDK jar. The Agent APK and Genie APK both
|
||||
package the Android `codex` binary as `libcodex.so`, so `just android-build`
|
||||
must run before `:app:assembleDebug` and `:genie:assembleDebug`.
|
||||
|
||||
If `cargo-ndk` cannot find your NDK, set:
|
||||
|
||||
```bash
|
||||
@@ -60,16 +66,16 @@ Build outputs:
|
||||
|
||||
- `target/android/aarch64-linux-android/release/codex`
|
||||
- `target/android/x86_64-linux-android/release/codex`
|
||||
|
||||
## Run On Device
|
||||
|
||||
Example for `arm64-v8a`:
|
||||
|
||||
```bash
|
||||
adb push target/android/aarch64-linux-android/release/codex /data/local/tmp/codex
|
||||
adb shell chmod +x /data/local/tmp/codex
|
||||
adb shell /data/local/tmp/codex --help
|
||||
adb push target/android/aarch64-linux-android/release/codex /data/local/tmp/codex-bin
|
||||
adb shell chmod +x /data/local/tmp/codex-bin
|
||||
adb shell /data/local/tmp/codex-bin --help
|
||||
```
|
||||
|
||||
## Authentication on Android
|
||||
|
||||
There are two reliable approaches when running the CLI from `adb shell`:
|
||||
@@ -77,9 +83,10 @@ There are two reliable approaches when running the CLI from `adb shell`:
|
||||
1) ChatGPT login via device code (recommended)
|
||||
|
||||
```bash
|
||||
adb shell /data/local/tmp/codex --device-auth
|
||||
adb shell /data/local/tmp/codex-bin --device-auth
|
||||
```
|
||||
This prints a URL and code. Open the URL on your host and enter the code.
|
||||
|
||||
The Agent app now owns authentication directly through the hosted Agent runtime.
|
||||
|
||||
2) MCP OAuth login via host browser + `adb forward`
|
||||
|
||||
@@ -91,7 +98,7 @@ from host to device so the redirect can reach the device.
|
||||
adb forward tcp:8765 tcp:8765
|
||||
|
||||
# Start the login; the URL will be printed.
|
||||
adb shell /data/local/tmp/codex mcp login <server_name> --callback-port 8765 --host-browser
|
||||
adb shell /data/local/tmp/codex-bin mcp login <server_name> --callback-port 8765 --host-browser
|
||||
```
|
||||
|
||||
Open the printed URL on your host. When the provider redirects to
|
||||
|
||||
1
justfile
1
justfile
@@ -84,6 +84,7 @@ android-build:
|
||||
profile_args=(--profile android-release-no-lto)
|
||||
fi
|
||||
CARGO_TARGET_DIR=target/android cargo ndk --platform 26 -t arm64-v8a -t x86_64 build -p codex-cli "${profile_args[@]}" --bin codex
|
||||
|
||||
# Run the MCP server
|
||||
mcp-server-run *args:
|
||||
cargo run -p codex-mcp-server -- "$@"
|
||||
|
||||
Reference in New Issue
Block a user