[App-server] v2 for account/updated and account/logout (#6175)

V2 for `account/updated` and `account/logout` for app server. correspond
to old `authStatusChange` and `LogoutChatGpt` respectively. Followup PRs
will make other v2 endpoints call `account/updated` instead of
`authStatusChange` too.
This commit is contained in:
Celia Chen
2025-11-03 22:01:33 -08:00
committed by GitHub
parent dc2f26f7b5
commit d3187dbc17
11 changed files with 200 additions and 26 deletions

View File

@@ -4,6 +4,7 @@ use crate::fuzzy_file_search::run_fuzzy_file_search;
use crate::models::supported_models;
use crate::outgoing_message::OutgoingMessageSender;
use crate::outgoing_message::OutgoingNotification;
use codex_app_server_protocol::AccountUpdatedNotification;
use codex_app_server_protocol::AddConversationListenerParams;
use codex_app_server_protocol::AddConversationSubscriptionResponse;
use codex_app_server_protocol::ApplyPatchApprovalParams;
@@ -200,8 +201,7 @@ impl CodexMessageProcessor {
request_id,
params: _,
} => {
self.send_unimplemented_error(request_id, "account/logout")
.await;
self.logout_v2(request_id).await;
}
ClientRequest::GetAccount {
request_id,
@@ -250,7 +250,7 @@ impl CodexMessageProcessor {
request_id,
params: _,
} => {
self.logout_chatgpt(request_id).await;
self.logout_v1(request_id).await;
}
ClientRequest::GetAuthStatus { request_id, params } => {
self.get_auth_status(request_id, params).await;
@@ -494,9 +494,9 @@ impl CodexMessageProcessor {
}
}
async fn logout_chatgpt(&mut self, request_id: RequestId) {
async fn logout_common(&mut self) -> std::result::Result<Option<AuthMode>, JSONRPCErrorError> {
// Cancel any active login attempt.
{
// Cancel any active login attempt.
let mut guard = self.active_login.lock().await;
if let Some(active) = guard.take() {
active.drop();
@@ -504,31 +504,61 @@ impl CodexMessageProcessor {
}
if let Err(err) = self.auth_manager.logout() {
let error = JSONRPCErrorError {
return Err(JSONRPCErrorError {
code: INTERNAL_ERROR_CODE,
message: format!("logout failed: {err}"),
data: None,
};
self.outgoing.send_error(request_id, error).await;
return;
});
}
self.outgoing
.send_response(
request_id,
codex_app_server_protocol::LogoutChatGptResponse {},
)
.await;
// Reflect the current auth method after logout (likely None).
Ok(self.auth_manager.auth().map(|auth| auth.mode))
}
// Send auth status change notification reflecting the current auth mode
// after logout.
let current_auth_method = self.auth_manager.auth().map(|auth| auth.mode);
let payload = AuthStatusChangeNotification {
auth_method: current_auth_method,
};
self.outgoing
.send_server_notification(ServerNotification::AuthStatusChange(payload))
.await;
async fn logout_v1(&mut self, request_id: RequestId) {
match self.logout_common().await {
Ok(current_auth_method) => {
self.outgoing
.send_response(
request_id,
codex_app_server_protocol::LogoutChatGptResponse {},
)
.await;
let payload = AuthStatusChangeNotification {
auth_method: current_auth_method,
};
self.outgoing
.send_server_notification(ServerNotification::AuthStatusChange(payload))
.await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
}
}
}
async fn logout_v2(&mut self, request_id: RequestId) {
match self.logout_common().await {
Ok(current_auth_method) => {
self.outgoing
.send_response(
request_id,
codex_app_server_protocol::LogoutAccountResponse {},
)
.await;
let payload_v2 = AccountUpdatedNotification {
auth_method: current_auth_method,
};
self.outgoing
.send_server_notification(ServerNotification::AccountUpdated(payload_v2))
.await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
}
}
}
async fn get_auth_status(

View File

@@ -141,6 +141,8 @@ pub(crate) struct OutgoingError {
#[cfg(test)]
mod tests {
use codex_app_server_protocol::AccountUpdatedNotification;
use codex_app_server_protocol::AuthMode;
use codex_app_server_protocol::LoginChatGptCompleteNotification;
use codex_protocol::protocol::RateLimitSnapshot;
use codex_protocol::protocol::RateLimitWindow;
@@ -204,4 +206,24 @@ mod tests {
"ensure the notification serializes correctly"
);
}
#[test]
fn verify_account_updated_notification_serialization() {
let notification = ServerNotification::AccountUpdated(AccountUpdatedNotification {
auth_method: Some(AuthMode::ApiKey),
});
let jsonrpc_notification = OutgoingMessage::AppServerNotification(notification);
assert_eq!(
json!({
"method": "account/updated",
"params": {
"authMethod": "apikey"
},
}),
serde_json::to_value(jsonrpc_notification)
.expect("ensure the notification serializes correctly"),
"ensure the notification serializes correctly"
);
}
}