mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
Merge 0166c1b156 into sapling-pr-archive-bolinfest
This commit is contained in:
@@ -30,7 +30,7 @@ pub enum AuthMode {
|
||||
/// OpenAI API key provided by the caller and stored by Codex.
|
||||
ApiKey,
|
||||
/// ChatGPT OAuth managed by Codex (tokens persisted and refreshed by Codex).
|
||||
ChatGPT,
|
||||
ChatGpt,
|
||||
/// [UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE.
|
||||
///
|
||||
/// ChatGPT auth tokens are supplied by an external host app and are only
|
||||
@@ -38,7 +38,7 @@ pub enum AuthMode {
|
||||
#[serde(rename = "chatgptAuthTokens")]
|
||||
#[ts(rename = "chatgptAuthTokens")]
|
||||
#[strum(serialize = "chatgptAuthTokens")]
|
||||
ChatgptAuthTokens,
|
||||
ChatGptAuthTokens,
|
||||
}
|
||||
|
||||
/// Generates an `enum ClientRequest` where each variant is a request that the
|
||||
@@ -549,9 +549,9 @@ server_request_definitions! {
|
||||
response: v2::DynamicToolCallResponse,
|
||||
},
|
||||
|
||||
ChatgptAuthTokensRefresh => "account/chatgptAuthTokens/refresh" {
|
||||
params: v2::ChatgptAuthTokensRefreshParams,
|
||||
response: v2::ChatgptAuthTokensRefreshResponse,
|
||||
ChatGptAuthTokensRefresh => "account/chatgptAuthTokens/refresh" {
|
||||
params: v2::ChatGptAuthTokensRefreshParams,
|
||||
response: v2::ChatGptAuthTokensRefreshResponse,
|
||||
},
|
||||
|
||||
/// DEPRECATED APIs below
|
||||
@@ -776,10 +776,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn serialize_chatgpt_auth_tokens_refresh_request() -> Result<()> {
|
||||
let request = ServerRequest::ChatgptAuthTokensRefresh {
|
||||
let request = ServerRequest::ChatGptAuthTokensRefresh {
|
||||
request_id: RequestId::Integer(8),
|
||||
params: v2::ChatgptAuthTokensRefreshParams {
|
||||
reason: v2::ChatgptAuthTokensRefreshReason::Unauthorized,
|
||||
params: v2::ChatGptAuthTokensRefreshParams {
|
||||
reason: v2::ChatGptAuthTokensRefreshReason::Unauthorized,
|
||||
previous_account_id: Some("org-123".to_string()),
|
||||
},
|
||||
};
|
||||
@@ -855,7 +855,7 @@ mod tests {
|
||||
fn serialize_account_login_chatgpt() -> Result<()> {
|
||||
let request = ClientRequest::LoginAccount {
|
||||
request_id: RequestId::Integer(3),
|
||||
params: v2::LoginAccountParams::Chatgpt,
|
||||
params: v2::LoginAccountParams::ChatGpt,
|
||||
};
|
||||
assert_eq!(
|
||||
json!({
|
||||
@@ -890,7 +890,7 @@ mod tests {
|
||||
fn serialize_account_login_chatgpt_auth_tokens() -> Result<()> {
|
||||
let request = ClientRequest::LoginAccount {
|
||||
request_id: RequestId::Integer(5),
|
||||
params: v2::LoginAccountParams::ChatgptAuthTokens {
|
||||
params: v2::LoginAccountParams::ChatGptAuthTokens {
|
||||
access_token: "access-token".to_string(),
|
||||
id_token: "id-token".to_string(),
|
||||
},
|
||||
@@ -941,7 +941,7 @@ mod tests {
|
||||
serde_json::to_value(&api_key)?,
|
||||
);
|
||||
|
||||
let chatgpt = v2::Account::Chatgpt {
|
||||
let chatgpt = v2::Account::ChatGpt {
|
||||
email: "user@example.com".to_string(),
|
||||
plan_type: PlanType::Plus,
|
||||
};
|
||||
|
||||
@@ -817,7 +817,7 @@ pub enum Account {
|
||||
|
||||
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
||||
Chatgpt { email: String, plan_type: PlanType },
|
||||
ChatGpt { email: String, plan_type: PlanType },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
@@ -834,12 +834,12 @@ pub enum LoginAccountParams {
|
||||
},
|
||||
#[serde(rename = "chatgpt")]
|
||||
#[ts(rename = "chatgpt")]
|
||||
Chatgpt,
|
||||
ChatGpt,
|
||||
/// [UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE.
|
||||
/// The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.
|
||||
#[serde(rename = "chatgptAuthTokens")]
|
||||
#[ts(rename = "chatgptAuthTokens")]
|
||||
ChatgptAuthTokens {
|
||||
ChatGptAuthTokens {
|
||||
/// ID token (JWT) supplied by the client.
|
||||
///
|
||||
/// This token is used for identity and account metadata (email, plan type,
|
||||
@@ -865,7 +865,7 @@ pub enum LoginAccountResponse {
|
||||
ApiKey {},
|
||||
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
||||
Chatgpt {
|
||||
ChatGpt {
|
||||
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
||||
// Convert to/from UUIDs at the application layer as needed.
|
||||
login_id: String,
|
||||
@@ -874,7 +874,7 @@ pub enum LoginAccountResponse {
|
||||
},
|
||||
#[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
ChatgptAuthTokens {},
|
||||
ChatGptAuthTokens {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
@@ -908,7 +908,7 @@ pub struct LogoutAccountResponse {}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ChatgptAuthTokensRefreshReason {
|
||||
pub enum ChatGptAuthTokensRefreshReason {
|
||||
/// Codex attempted a backend request and received `401 Unauthorized`.
|
||||
Unauthorized,
|
||||
}
|
||||
@@ -916,8 +916,8 @@ pub enum ChatgptAuthTokensRefreshReason {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ChatgptAuthTokensRefreshParams {
|
||||
pub reason: ChatgptAuthTokensRefreshReason,
|
||||
pub struct ChatGptAuthTokensRefreshParams {
|
||||
pub reason: ChatGptAuthTokensRefreshReason,
|
||||
/// Workspace/account identifier that Codex was previously using.
|
||||
///
|
||||
/// Clients that manage multiple accounts/workspaces can use this as a hint
|
||||
@@ -931,7 +931,7 @@ pub struct ChatgptAuthTokensRefreshParams {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ChatgptAuthTokensRefreshResponse {
|
||||
pub struct ChatGptAuthTokensRefreshResponse {
|
||||
pub id_token: String,
|
||||
pub access_token: String,
|
||||
}
|
||||
|
||||
@@ -613,10 +613,10 @@ impl CodexMessageProcessor {
|
||||
self.login_api_key_v2(request_id, LoginApiKeyParams { api_key })
|
||||
.await;
|
||||
}
|
||||
LoginAccountParams::Chatgpt => {
|
||||
LoginAccountParams::ChatGpt => {
|
||||
self.login_chatgpt_v2(request_id).await;
|
||||
}
|
||||
LoginAccountParams::ChatgptAuthTokens {
|
||||
LoginAccountParams::ChatGptAuthTokens {
|
||||
id_token,
|
||||
access_token,
|
||||
} => {
|
||||
@@ -645,7 +645,7 @@ impl CodexMessageProcessor {
|
||||
|
||||
if matches!(
|
||||
self.config.forced_login_method,
|
||||
Some(ForcedLoginMethod::Chatgpt)
|
||||
Some(ForcedLoginMethod::ChatGpt)
|
||||
) {
|
||||
return Err(JSONRPCErrorError {
|
||||
code: INVALID_REQUEST_ERROR_CODE,
|
||||
@@ -935,7 +935,7 @@ impl CodexMessageProcessor {
|
||||
}
|
||||
});
|
||||
|
||||
let response = codex_app_server_protocol::LoginAccountResponse::Chatgpt {
|
||||
let response = codex_app_server_protocol::LoginAccountResponse::ChatGpt {
|
||||
login_id: login_id.to_string(),
|
||||
auth_url,
|
||||
};
|
||||
@@ -1081,7 +1081,7 @@ impl CodexMessageProcessor {
|
||||
self.auth_manager.reload();
|
||||
|
||||
self.outgoing
|
||||
.send_response(request_id, LoginAccountResponse::ChatgptAuthTokens {})
|
||||
.send_response(request_id, LoginAccountResponse::ChatGptAuthTokens {})
|
||||
.await;
|
||||
|
||||
let payload_login_completed = AccountLoginCompletedNotification {
|
||||
@@ -1251,7 +1251,7 @@ impl CodexMessageProcessor {
|
||||
let plan_type = auth.account_plan_type();
|
||||
|
||||
match (email, plan_type) {
|
||||
(Some(email), Some(plan_type)) => Account::Chatgpt { email, plan_type },
|
||||
(Some(email), Some(plan_type)) => Account::ChatGpt { email, plan_type },
|
||||
_ => {
|
||||
let error = JSONRPCErrorError {
|
||||
code: INVALID_REQUEST_ERROR_CODE,
|
||||
|
||||
@@ -6,9 +6,9 @@ use crate::config_api::ConfigApi;
|
||||
use crate::error_code::INVALID_REQUEST_ERROR_CODE;
|
||||
use crate::outgoing_message::OutgoingMessageSender;
|
||||
use async_trait::async_trait;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshParams;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshReason;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshResponse;
|
||||
use codex_app_server_protocol::ChatGptAuthTokensRefreshParams;
|
||||
use codex_app_server_protocol::ChatGptAuthTokensRefreshReason;
|
||||
use codex_app_server_protocol::ChatGptAuthTokensRefreshResponse;
|
||||
use codex_app_server_protocol::ClientInfo;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
use codex_app_server_protocol::ConfigBatchWriteParams;
|
||||
@@ -52,9 +52,9 @@ struct ExternalAuthRefreshBridge {
|
||||
}
|
||||
|
||||
impl ExternalAuthRefreshBridge {
|
||||
fn map_reason(reason: ExternalAuthRefreshReason) -> ChatgptAuthTokensRefreshReason {
|
||||
fn map_reason(reason: ExternalAuthRefreshReason) -> ChatGptAuthTokensRefreshReason {
|
||||
match reason {
|
||||
ExternalAuthRefreshReason::Unauthorized => ChatgptAuthTokensRefreshReason::Unauthorized,
|
||||
ExternalAuthRefreshReason::Unauthorized => ChatGptAuthTokensRefreshReason::Unauthorized,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,14 +65,14 @@ impl ExternalAuthRefresher for ExternalAuthRefreshBridge {
|
||||
&self,
|
||||
context: ExternalAuthRefreshContext,
|
||||
) -> std::io::Result<ExternalAuthTokens> {
|
||||
let params = ChatgptAuthTokensRefreshParams {
|
||||
let params = ChatGptAuthTokensRefreshParams {
|
||||
reason: Self::map_reason(context.reason),
|
||||
previous_account_id: context.previous_account_id,
|
||||
};
|
||||
|
||||
let (request_id, rx) = self
|
||||
.outgoing
|
||||
.send_request_with_id(ServerRequestPayload::ChatgptAuthTokensRefresh(params))
|
||||
.send_request_with_id(ServerRequestPayload::ChatGptAuthTokensRefresh(params))
|
||||
.await;
|
||||
|
||||
let result = match timeout(EXTERNAL_AUTH_REFRESH_TIMEOUT, rx).await {
|
||||
@@ -88,7 +88,7 @@ impl ExternalAuthRefresher for ExternalAuthRefreshBridge {
|
||||
}
|
||||
};
|
||||
|
||||
let response: ChatgptAuthTokensRefreshResponse =
|
||||
let response: ChatGptAuthTokensRefreshResponse =
|
||||
serde_json::from_value(result).map_err(std::io::Error::other)?;
|
||||
|
||||
Ok(ExternalAuthTokens {
|
||||
|
||||
@@ -159,7 +159,7 @@ pub fn write_chatgpt_auth(
|
||||
let last_refresh = fixture.last_refresh.unwrap_or_else(|| Some(Utc::now()));
|
||||
|
||||
let auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(tokens),
|
||||
last_refresh,
|
||||
|
||||
@@ -306,7 +306,7 @@ impl McpProcess {
|
||||
id_token: String,
|
||||
access_token: String,
|
||||
) -> anyhow::Result<i64> {
|
||||
let params = LoginAccountParams::ChatgptAuthTokens {
|
||||
let params = LoginAccountParams::ChatGptAuthTokens {
|
||||
id_token,
|
||||
access_token,
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ async fn get_config_toml_parses_all_fields() -> Result<()> {
|
||||
exclude_slash_tmp: Some(true),
|
||||
}),
|
||||
forced_chatgpt_workspace_id: Some("12345678-0000-0000-0000-000000000000".into()),
|
||||
forced_login_method: Some(ForcedLoginMethod::Chatgpt),
|
||||
forced_login_method: Some(ForcedLoginMethod::ChatGpt),
|
||||
model: Some("gpt-5.1-codex-max".into()),
|
||||
model_reasoning_effort: Some(ReasoningEffort::High),
|
||||
model_reasoning_summary: Some(ReasoningSummary::Detailed),
|
||||
|
||||
@@ -13,8 +13,8 @@ use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::CancelLoginAccountParams;
|
||||
use codex_app_server_protocol::CancelLoginAccountResponse;
|
||||
use codex_app_server_protocol::CancelLoginAccountStatus;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshReason;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshResponse;
|
||||
use codex_app_server_protocol::ChatGptAuthTokensRefreshReason;
|
||||
use codex_app_server_protocol::ChatGptAuthTokensRefreshResponse;
|
||||
use codex_app_server_protocol::GetAccountParams;
|
||||
use codex_app_server_protocol::GetAccountResponse;
|
||||
use codex_app_server_protocol::JSONRPCError;
|
||||
@@ -186,7 +186,7 @@ async fn set_auth_token_updates_account_and_notifies() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
|
||||
let note = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
@@ -197,7 +197,7 @@ async fn set_auth_token_updates_account_and_notifies() -> Result<()> {
|
||||
let ServerNotification::AccountUpdated(payload) = parsed else {
|
||||
bail!("unexpected notification: {parsed:?}");
|
||||
};
|
||||
assert_eq!(payload.auth_mode, Some(AuthMode::ChatgptAuthTokens));
|
||||
assert_eq!(payload.auth_mode, Some(AuthMode::ChatGptAuthTokens));
|
||||
|
||||
let get_id = mcp
|
||||
.send_get_account_request(GetAccountParams {
|
||||
@@ -213,7 +213,7 @@ async fn set_auth_token_updates_account_and_notifies() -> Result<()> {
|
||||
assert_eq!(
|
||||
account,
|
||||
GetAccountResponse {
|
||||
account: Some(Account::Chatgpt {
|
||||
account: Some(Account::ChatGpt {
|
||||
email: "embedded@example.com".to_string(),
|
||||
plan_type: AccountPlanType::Pro,
|
||||
}),
|
||||
@@ -255,7 +255,7 @@ async fn account_read_refresh_token_is_noop_in_external_mode() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -276,7 +276,7 @@ async fn account_read_refresh_token_is_noop_in_external_mode() -> Result<()> {
|
||||
assert_eq!(
|
||||
account,
|
||||
GetAccountResponse {
|
||||
account: Some(Account::Chatgpt {
|
||||
account: Some(Account::ChatGpt {
|
||||
email: "embedded@example.com".to_string(),
|
||||
plan_type: AccountPlanType::Pro,
|
||||
}),
|
||||
@@ -307,11 +307,11 @@ async fn respond_to_refresh_request(
|
||||
mcp.read_stream_until_request_message(),
|
||||
)
|
||||
.await??;
|
||||
let ServerRequest::ChatgptAuthTokensRefresh { request_id, params } = refresh_req else {
|
||||
let ServerRequest::ChatGptAuthTokensRefresh { request_id, params } = refresh_req else {
|
||||
bail!("expected account/chatgptAuthTokens/refresh request, got {refresh_req:?}");
|
||||
};
|
||||
assert_eq!(params.reason, ChatgptAuthTokensRefreshReason::Unauthorized);
|
||||
let response = ChatgptAuthTokensRefreshResponse {
|
||||
assert_eq!(params.reason, ChatGptAuthTokensRefreshReason::Unauthorized);
|
||||
let response = ChatGptAuthTokensRefreshResponse {
|
||||
access_token: access_token.to_string(),
|
||||
id_token: id_token.to_string(),
|
||||
};
|
||||
@@ -379,7 +379,7 @@ async fn external_auth_refreshes_on_unauthorized() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -475,7 +475,7 @@ async fn external_auth_refresh_error_fails_turn() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -511,7 +511,7 @@ async fn external_auth_refresh_error_fails_turn() -> Result<()> {
|
||||
mcp.read_stream_until_request_message(),
|
||||
)
|
||||
.await??;
|
||||
let ServerRequest::ChatgptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
let ServerRequest::ChatGptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
bail!("expected account/chatgptAuthTokens/refresh request, got {refresh_req:?}");
|
||||
};
|
||||
|
||||
@@ -593,7 +593,7 @@ async fn external_auth_refresh_mismatched_workspace_fails_turn() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -629,13 +629,13 @@ async fn external_auth_refresh_mismatched_workspace_fails_turn() -> Result<()> {
|
||||
mcp.read_stream_until_request_message(),
|
||||
)
|
||||
.await??;
|
||||
let ServerRequest::ChatgptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
let ServerRequest::ChatGptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
bail!("expected account/chatgptAuthTokens/refresh request, got {refresh_req:?}");
|
||||
};
|
||||
|
||||
mcp.send_response(
|
||||
request_id,
|
||||
serde_json::to_value(ChatgptAuthTokensRefreshResponse {
|
||||
serde_json::to_value(ChatGptAuthTokensRefreshResponse {
|
||||
access_token: "access-refreshed".to_string(),
|
||||
id_token: refreshed_id_token,
|
||||
})?,
|
||||
@@ -703,7 +703,7 @@ async fn external_auth_refresh_invalid_id_token_fails_turn() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -739,13 +739,13 @@ async fn external_auth_refresh_invalid_id_token_fails_turn() -> Result<()> {
|
||||
mcp.read_stream_until_request_message(),
|
||||
)
|
||||
.await??;
|
||||
let ServerRequest::ChatgptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
let ServerRequest::ChatGptAuthTokensRefresh { request_id, .. } = refresh_req else {
|
||||
bail!("expected account/chatgptAuthTokens/refresh request, got {refresh_req:?}");
|
||||
};
|
||||
|
||||
mcp.send_response(
|
||||
request_id,
|
||||
serde_json::to_value(ChatgptAuthTokensRefreshResponse {
|
||||
serde_json::to_value(ChatGptAuthTokensRefreshResponse {
|
||||
access_token: "access-refreshed".to_string(),
|
||||
id_token: "not-a-jwt".to_string(),
|
||||
})?,
|
||||
@@ -896,7 +896,7 @@ async fn login_account_chatgpt_start_can_be_cancelled() -> Result<()> {
|
||||
.await??;
|
||||
|
||||
let login: LoginAccountResponse = to_response(resp)?;
|
||||
let LoginAccountResponse::Chatgpt { login_id, auth_url } = login else {
|
||||
let LoginAccountResponse::ChatGpt { login_id, auth_url } = login else {
|
||||
bail!("unexpected login response: {login:?}");
|
||||
};
|
||||
assert!(
|
||||
@@ -963,7 +963,7 @@ async fn set_auth_token_cancels_active_chatgpt_login() -> Result<()> {
|
||||
.await??;
|
||||
|
||||
let login: LoginAccountResponse = to_response(resp)?;
|
||||
let LoginAccountResponse::Chatgpt { login_id, .. } = login else {
|
||||
let LoginAccountResponse::ChatGpt { login_id, .. } = login else {
|
||||
bail!("unexpected login response: {login:?}");
|
||||
};
|
||||
|
||||
@@ -984,7 +984,7 @@ async fn set_auth_token_cancels_active_chatgpt_login() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let response: LoginAccountResponse = to_response(set_resp)?;
|
||||
assert_eq!(response, LoginAccountResponse::ChatgptAuthTokens {});
|
||||
assert_eq!(response, LoginAccountResponse::ChatGptAuthTokens {});
|
||||
let _updated = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("account/updated"),
|
||||
@@ -1033,7 +1033,7 @@ async fn login_account_chatgpt_includes_forced_workspace_query_param() -> Result
|
||||
.await??;
|
||||
|
||||
let login: LoginAccountResponse = to_response(resp)?;
|
||||
let LoginAccountResponse::Chatgpt { auth_url, .. } = login else {
|
||||
let LoginAccountResponse::ChatGpt { auth_url, .. } = login else {
|
||||
bail!("unexpected login response: {login:?}");
|
||||
};
|
||||
assert!(
|
||||
@@ -1186,7 +1186,7 @@ async fn get_account_with_chatgpt() -> Result<()> {
|
||||
let received: GetAccountResponse = to_response(resp)?;
|
||||
|
||||
let expected = GetAccountResponse {
|
||||
account: Some(Account::Chatgpt {
|
||||
account: Some(Account::ChatGpt {
|
||||
email: "user@example.com".to_string(),
|
||||
plan_type: AccountPlanType::Pro,
|
||||
}),
|
||||
|
||||
@@ -78,7 +78,7 @@ pub async fn run_login_with_api_key(
|
||||
) -> ! {
|
||||
let config = load_config_or_exit(cli_config_overrides).await;
|
||||
|
||||
if matches!(config.forced_login_method, Some(ForcedLoginMethod::Chatgpt)) {
|
||||
if matches!(config.forced_login_method, Some(ForcedLoginMethod::ChatGpt)) {
|
||||
eprintln!("{API_KEY_LOGIN_DISABLED_MESSAGE}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
@@ -236,11 +236,11 @@ pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! {
|
||||
std::process::exit(1);
|
||||
}
|
||||
},
|
||||
AuthMode::ChatGPT => {
|
||||
AuthMode::ChatGpt => {
|
||||
eprintln!("Logged in using ChatGPT");
|
||||
std::process::exit(0);
|
||||
}
|
||||
AuthMode::ChatgptAuthTokens => {
|
||||
AuthMode::ChatGptAuthTokens => {
|
||||
eprintln!("Logged in using ChatGPT (external tokens)");
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
@@ -167,11 +167,11 @@ impl CodexAuth {
|
||||
};
|
||||
|
||||
match auth_mode {
|
||||
ApiAuthMode::ChatGPT => {
|
||||
ApiAuthMode::ChatGpt => {
|
||||
let storage = create_auth_storage(codex_home.to_path_buf(), storage_mode);
|
||||
Ok(Self::ChatGpt(ChatGptAuth { state, storage }))
|
||||
}
|
||||
ApiAuthMode::ChatgptAuthTokens => {
|
||||
ApiAuthMode::ChatGptAuthTokens => {
|
||||
Ok(Self::ChatGptAuthTokens(ChatGptAuthTokens { state }))
|
||||
}
|
||||
ApiAuthMode::ApiKey => unreachable!("api key mode is handled above"),
|
||||
@@ -196,8 +196,8 @@ impl CodexAuth {
|
||||
pub fn api_auth_mode(&self) -> ApiAuthMode {
|
||||
match self {
|
||||
Self::ApiKey(_) => ApiAuthMode::ApiKey,
|
||||
Self::ChatGpt(_) => ApiAuthMode::ChatGPT,
|
||||
Self::ChatGptAuthTokens(_) => ApiAuthMode::ChatgptAuthTokens,
|
||||
Self::ChatGpt(_) => ApiAuthMode::ChatGpt,
|
||||
Self::ChatGptAuthTokens(_) => ApiAuthMode::ChatGptAuthTokens,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ impl CodexAuth {
|
||||
/// Consider this private to integration tests.
|
||||
pub fn create_dummy_chatgpt_auth_for_testing() -> Self {
|
||||
let auth_dot_json = AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::ChatGPT),
|
||||
auth_mode: Some(ApiAuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(TokenData {
|
||||
id_token: Default::default(),
|
||||
@@ -436,12 +436,12 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
|
||||
if let Some(required_method) = config.forced_login_method {
|
||||
let method_violation = match (required_method, auth.internal_auth_mode()) {
|
||||
(ForcedLoginMethod::Api, AuthMode::ApiKey) => None,
|
||||
(ForcedLoginMethod::Chatgpt, AuthMode::ChatGPT) => None,
|
||||
(ForcedLoginMethod::ChatGpt, AuthMode::ChatGPT) => None,
|
||||
(ForcedLoginMethod::Api, AuthMode::ChatGPT) => Some(
|
||||
"API key login is required, but ChatGPT is currently being used. Logging out."
|
||||
.to_string(),
|
||||
),
|
||||
(ForcedLoginMethod::Chatgpt, AuthMode::ApiKey) => Some(
|
||||
(ForcedLoginMethod::ChatGpt, AuthMode::ApiKey) => Some(
|
||||
"ChatGPT login is required, but an API key is currently being used. Logging out."
|
||||
.to_string(),
|
||||
),
|
||||
@@ -727,7 +727,7 @@ impl AuthDotJson {
|
||||
};
|
||||
|
||||
Self {
|
||||
auth_mode: Some(ApiAuthMode::ChatgptAuthTokens),
|
||||
auth_mode: Some(ApiAuthMode::ChatGptAuthTokens),
|
||||
openai_api_key: None,
|
||||
tokens: Some(tokens),
|
||||
last_refresh: Some(Utc::now()),
|
||||
@@ -750,14 +750,14 @@ impl AuthDotJson {
|
||||
if self.openai_api_key.is_some() {
|
||||
return ApiAuthMode::ApiKey;
|
||||
}
|
||||
ApiAuthMode::ChatGPT
|
||||
ApiAuthMode::ChatGpt
|
||||
}
|
||||
|
||||
fn storage_mode(
|
||||
&self,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
) -> AuthCredentialsStoreMode {
|
||||
if self.resolved_mode() == ApiAuthMode::ChatgptAuthTokens {
|
||||
if self.resolved_mode() == ApiAuthMode::ChatGptAuthTokens {
|
||||
AuthCredentialsStoreMode::Ephemeral
|
||||
} else {
|
||||
auth_credentials_store_mode
|
||||
@@ -1547,7 +1547,7 @@ mod tests {
|
||||
login_with_api_key(codex_home.path(), "sk-test", AuthCredentialsStoreMode::File)
|
||||
.expect("seed api key");
|
||||
|
||||
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None).await;
|
||||
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::ChatGpt), None).await;
|
||||
|
||||
let err = super::enforce_login_restrictions(&config)
|
||||
.expect_err("expected method mismatch to error");
|
||||
@@ -1628,7 +1628,7 @@ mod tests {
|
||||
let _guard = EnvVarGuard::set(CODEX_API_KEY_ENV_VAR, "sk-env");
|
||||
let codex_home = tempdir().unwrap();
|
||||
|
||||
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None).await;
|
||||
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::ChatGpt), None).await;
|
||||
|
||||
let err = super::enforce_login_restrictions(&config)
|
||||
.expect_err("environment API key should not satisfy forced ChatGPT login");
|
||||
|
||||
@@ -565,7 +565,7 @@ mod tests {
|
||||
let auth_file = get_auth_file(codex_home.path());
|
||||
std::fs::write(&auth_file, "stale")?;
|
||||
let auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(TokenData {
|
||||
id_token: Default::default(),
|
||||
|
||||
@@ -4838,7 +4838,7 @@ mod tests {
|
||||
model_info.slug.as_str(),
|
||||
None,
|
||||
Some("test@test.com".to_string()),
|
||||
Some(AuthMode::ChatGPT),
|
||||
Some(AuthMode::ChatGpt),
|
||||
false,
|
||||
"test".to_string(),
|
||||
session_source,
|
||||
|
||||
@@ -37,6 +37,8 @@ When in doubt: if the action would reasonably be described as "doing the work" r
|
||||
|
||||
Begin by grounding yourself in the actual environment. Eliminate unknowns in the prompt by discovering facts, not by asking the user. Resolve all questions that can be answered through exploration or inspection. Identify missing or ambiguous details only if they cannot be derived from the environment. Silent exploration between turns is allowed and encouraged.
|
||||
|
||||
Before asking the user any question, perform at least one targeted non-mutating exploration pass (for example: search relevant files, inspect likely entrypoints/configs, confirm current implementation shape), unless no local environment/repo is available.
|
||||
|
||||
Do not ask questions that can be answered from the repo or system (for example, "where is this struct?" or "which UI component should we use?" when exploration can make it clear). Only ask once you have exhausted reasonable non-mutating exploration.
|
||||
|
||||
## PHASE 2 — Intent chat (what they actually want)
|
||||
@@ -97,6 +99,7 @@ Only output the final plan when it is decision complete and leaves no decisions
|
||||
The final plan must be plan-only and include:
|
||||
|
||||
* A clear title
|
||||
* A TL;DR section (3–5 bullets)
|
||||
* Exact file paths to change
|
||||
* Exact structures or shapes to introduce or modify
|
||||
* Exact function, method, type, and variable names and signatures
|
||||
|
||||
@@ -71,7 +71,7 @@ async fn responses_stream_includes_subagent_header_on_review() {
|
||||
let config = Arc::new(config);
|
||||
|
||||
let conversation_id = ThreadId::new();
|
||||
let auth_mode = AuthMode::ChatGPT;
|
||||
let auth_mode = AuthMode::ChatGpt;
|
||||
let session_source = SessionSource::SubAgent(SubAgentSource::Review);
|
||||
let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config);
|
||||
let otel_manager = OtelManager::new(
|
||||
@@ -169,7 +169,7 @@ async fn responses_stream_includes_subagent_header_on_other() {
|
||||
let config = Arc::new(config);
|
||||
|
||||
let conversation_id = ThreadId::new();
|
||||
let auth_mode = AuthMode::ChatGPT;
|
||||
let auth_mode = AuthMode::ChatGpt;
|
||||
let session_source = SessionSource::SubAgent(SubAgentSource::Other("my-task".to_string()));
|
||||
let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ async fn refresh_token_succeeds_updates_storage() -> Result<()> {
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -113,7 +113,7 @@ async fn returns_fresh_tokens_as_is() -> Result<()> {
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -159,7 +159,7 @@ async fn refreshes_token_when_last_refresh_is_stale() -> Result<()> {
|
||||
let stale_refresh = Utc::now() - Duration::days(9);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(stale_refresh),
|
||||
@@ -218,7 +218,7 @@ async fn refresh_token_returns_permanent_error_for_expired_refresh_token() -> Re
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -268,7 +268,7 @@ async fn refresh_token_returns_transient_error_on_server_failure() -> Result<()>
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -320,7 +320,7 @@ async fn unauthorized_recovery_reloads_then_refreshes_tokens() -> Result<()> {
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -329,7 +329,7 @@ async fn unauthorized_recovery_reloads_then_refreshes_tokens() -> Result<()> {
|
||||
|
||||
let disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
let disk_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(disk_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -412,7 +412,7 @@ async fn unauthorized_recovery_skips_reload_on_account_mismatch() -> Result<()>
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(initial_tokens.clone()),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
@@ -427,7 +427,7 @@ async fn unauthorized_recovery_skips_reload_on_account_mismatch() -> Result<()>
|
||||
..disk_tokens.clone()
|
||||
};
|
||||
let disk_auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(disk_tokens),
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
|
||||
@@ -560,7 +560,7 @@ pub(crate) async fn persist_tokens_async(
|
||||
tokens.account_id = Some(acc.to_string());
|
||||
}
|
||||
let auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ChatGPT),
|
||||
auth_mode: Some(AuthMode::ChatGpt),
|
||||
openai_api_key: api_key,
|
||||
tokens: Some(tokens),
|
||||
last_refresh: Some(Utc::now()),
|
||||
|
||||
@@ -116,7 +116,7 @@ pub enum WebSearchMode {
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum ForcedLoginMethod {
|
||||
Chatgpt,
|
||||
ChatGpt,
|
||||
Api,
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ pub(crate) struct AuthModeWidget {
|
||||
|
||||
impl AuthModeWidget {
|
||||
fn is_api_login_allowed(&self) -> bool {
|
||||
!matches!(self.forced_login_method, Some(ForcedLoginMethod::Chatgpt))
|
||||
!matches!(self.forced_login_method, Some(ForcedLoginMethod::ChatGpt))
|
||||
}
|
||||
|
||||
fn is_chatgpt_login_allowed(&self) -> bool {
|
||||
@@ -663,7 +663,7 @@ impl AuthModeWidget {
|
||||
fn handle_existing_chatgpt_login(&mut self) -> bool {
|
||||
if matches!(
|
||||
self.login_status,
|
||||
LoginStatus::AuthMode(AuthMode::ChatGPT | AuthMode::ChatgptAuthTokens)
|
||||
LoginStatus::AuthMode(AuthMode::ChatGpt | AuthMode::ChatGptAuthTokens)
|
||||
) {
|
||||
*self.sign_in_state.write().unwrap() = SignInState::ChatGptSuccess;
|
||||
self.request_frame.schedule_frame();
|
||||
@@ -813,7 +813,7 @@ mod tests {
|
||||
AuthCredentialsStoreMode::File,
|
||||
),
|
||||
forced_chatgpt_workspace_id: None,
|
||||
forced_login_method: Some(ForcedLoginMethod::Chatgpt),
|
||||
forced_login_method: Some(ForcedLoginMethod::ChatGpt),
|
||||
animations_enabled: true,
|
||||
};
|
||||
(widget, codex_home)
|
||||
|
||||
Reference in New Issue
Block a user