Add codex apply to apply a patch created from the Codex remote agent (#1528)

In order to to this, I created a new `chatgpt` crate where we can put
any code that interacts directly with ChatGPT as opposed to the OpenAI
API. I added a disclaimer to the README for it that it should primarily
be modified by OpenAI employees.


https://github.com/user-attachments/assets/bb978e33-d2c9-4d8e-af28-c8c25b1988e8
This commit is contained in:
Gabriel Peal
2025-07-11 13:30:11 -04:00
committed by GitHub
parent 9e58076cf5
commit bfeb8c92a5
16 changed files with 559 additions and 16 deletions

View File

@@ -59,6 +59,13 @@ pub async fn login_with_chatgpt(
/// Attempt to read the `OPENAI_API_KEY` from the `auth.json` file in the given
/// `CODEX_HOME` directory, refreshing it, if necessary.
pub async fn try_read_openai_api_key(codex_home: &Path) -> std::io::Result<String> {
let auth_dot_json = try_read_auth_json(codex_home).await?;
Ok(auth_dot_json.openai_api_key)
}
/// Attempt to read and refresh the `auth.json` file in the given `CODEX_HOME` directory.
/// Returns the full AuthDotJson structure after refreshing if necessary.
pub async fn try_read_auth_json(codex_home: &Path) -> std::io::Result<AuthDotJson> {
let auth_path = codex_home.join("auth.json");
let mut file = std::fs::File::open(&auth_path)?;
let mut contents = String::new();
@@ -88,9 +95,9 @@ pub async fn try_read_openai_api_key(codex_home: &Path) -> std::io::Result<Strin
file.flush()?;
}
Ok(auth_dot_json.openai_api_key)
Ok(auth_dot_json)
} else {
Ok(auth_dot_json.openai_api_key)
Ok(auth_dot_json)
}
}
@@ -146,23 +153,24 @@ struct RefreshResponse {
/// Expected structure for $CODEX_HOME/auth.json.
#[derive(Deserialize, Serialize)]
struct AuthDotJson {
pub struct AuthDotJson {
#[serde(rename = "OPENAI_API_KEY")]
openai_api_key: String,
pub openai_api_key: String,
tokens: TokenData,
pub tokens: TokenData,
last_refresh: DateTime<Utc>,
pub last_refresh: DateTime<Utc>,
}
#[derive(Deserialize, Serialize)]
struct TokenData {
#[derive(Deserialize, Serialize, Clone)]
pub struct TokenData {
/// This is a JWT.
id_token: String,
pub id_token: String,
/// This is a JWT.
#[allow(dead_code)]
access_token: String,
pub access_token: String,
refresh_token: String,
pub refresh_token: String,
pub account_id: String,
}

View File

@@ -51,6 +51,7 @@ class TokenData:
id_token: str
access_token: str
refresh_token: str
account_id: str
@dataclass
@@ -240,20 +241,26 @@ class _ApiKeyHTTPHandler(http.server.BaseHTTPRequestHandler):
)
) as resp:
payload = json.loads(resp.read().decode())
# Extract chatgpt_account_id from id_token
id_token_parts = payload["id_token"].split(".")
if len(id_token_parts) != 3:
raise ValueError("Invalid ID token")
id_token_claims = _decode_jwt_segment(id_token_parts[1])
auth_claims = id_token_claims.get("https://api.openai.com/auth", {})
chatgpt_account_id = auth_claims.get("chatgpt_account_id", "")
token_data = TokenData(
id_token=payload["id_token"],
access_token=payload["access_token"],
refresh_token=payload["refresh_token"],
account_id=chatgpt_account_id,
)
id_token_parts = token_data.id_token.split(".")
if len(id_token_parts) != 3:
raise ValueError("Invalid ID token")
access_token_parts = token_data.access_token.split(".")
if len(access_token_parts) != 3:
raise ValueError("Invalid access token")
id_token_claims = _decode_jwt_segment(id_token_parts[1])
access_token_claims = _decode_jwt_segment(access_token_parts[1])
token_claims = id_token_claims.get("https://api.openai.com/auth", {})
@@ -375,6 +382,7 @@ def _write_auth_file(*, auth: AuthBundle, codex_home: str) -> bool:
"id_token": auth.token_data.id_token,
"access_token": auth.token_data.access_token,
"refresh_token": auth.token_data.refresh_token,
"account_id": auth.token_data.account_id,
},
"last_refresh": auth.last_refresh,
}