Revert "Option to Notify Workspace Owner When Usage Limit is Reached" (#17391)

Reverts openai/codex#16969

#sev3-2026-04-10-accountscheckversion-500s-for-openai-workspace-7300
This commit is contained in:
Shijie Rao
2026-04-10 16:33:13 -07:00
committed by GitHub
Unverified
parent a3be74143a
commit 930e5adb7e
82 changed files with 60 additions and 3233 deletions
@@ -116,8 +116,6 @@ use codex_app_server_protocol::SkillsConfigWriteResponse;
use codex_app_server_protocol::SkillsListParams;
use codex_app_server_protocol::SkillsListResponse;
use codex_app_server_protocol::Thread;
use codex_app_server_protocol::ThreadAddCreditsNudgeEmailParams;
use codex_app_server_protocol::ThreadAddCreditsNudgeEmailResponse;
use codex_app_server_protocol::ThreadArchiveParams;
use codex_app_server_protocol::ThreadArchiveResponse;
use codex_app_server_protocol::ThreadArchivedNotification;
@@ -186,7 +184,6 @@ use codex_app_server_protocol::WindowsSandboxSetupCompletedNotification;
use codex_app_server_protocol::WindowsSandboxSetupMode;
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
use codex_app_server_protocol::WindowsSandboxSetupStartResponse;
use codex_app_server_protocol::WorkspaceRole;
use codex_app_server_protocol::build_turns_from_rollout_items;
use codex_arg0::Arg0DispatchPaths;
use codex_backend_client::Client as BackendClient;
@@ -203,7 +200,6 @@ use codex_core::SteerInputError;
use codex_core::ThreadConfigSnapshot;
use codex_core::ThreadManager;
use codex_core::ThreadSortKey as CoreThreadSortKey;
use codex_core::WorkspaceRole as CoreWorkspaceRole;
use codex_core::append_thread_name;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
@@ -490,96 +486,6 @@ pub(crate) struct CodexMessageProcessorArgs {
pub(crate) log_db: Option<LogDbLayer>,
}
async fn resolve_workspace_role_and_owner_for_auth(
chatgpt_base_url: &str,
auth: Option<&CodexAuth>,
) -> (Option<WorkspaceRole>, Option<bool>) {
let ownership =
codex_core::resolve_workspace_role_and_owner_for_auth(chatgpt_base_url, auth).await;
(
ownership.workspace_role.map(workspace_role_to_v2),
ownership.is_workspace_owner,
)
}
fn workspace_role_to_v2(role: CoreWorkspaceRole) -> WorkspaceRole {
match role {
CoreWorkspaceRole::AccountOwner => WorkspaceRole::AccountOwner,
CoreWorkspaceRole::AccountAdmin => WorkspaceRole::AccountAdmin,
CoreWorkspaceRole::StandardUser => WorkspaceRole::StandardUser,
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct AuthIdentity {
auth_mode: AuthMode,
account_id: Option<String>,
account_email: Option<String>,
chatgpt_user_id: Option<String>,
}
fn auth_identity(auth: &CodexAuth) -> AuthIdentity {
AuthIdentity {
auth_mode: auth.api_auth_mode(),
account_id: auth.get_account_id(),
account_email: auth.get_account_email(),
chatgpt_user_id: auth.get_chatgpt_user_id(),
}
}
fn cached_workspace_role_and_owner_for_auth(
auth: Option<&CodexAuth>,
) -> (Option<WorkspaceRole>, Option<bool>) {
(None, auth.and_then(CodexAuth::is_workspace_owner))
}
fn account_updated_notification_for_auth(
auth: Option<&CodexAuth>,
workspace_role: Option<WorkspaceRole>,
is_workspace_owner: Option<bool>,
) -> AccountUpdatedNotification {
AccountUpdatedNotification {
auth_mode: auth.map(CodexAuth::api_auth_mode),
plan_type: auth.and_then(CodexAuth::account_plan_type),
workspace_role,
is_workspace_owner,
}
}
fn spawn_live_workspace_role_update_for_auth(
outgoing: Arc<OutgoingMessageSender>,
auth_manager: Arc<AuthManager>,
chatgpt_base_url: String,
auth: Option<CodexAuth>,
) {
let Some(auth) = auth.filter(CodexAuth::is_chatgpt_auth) else {
return;
};
let expected_identity = auth_identity(&auth);
tokio::spawn(async move {
let (workspace_role, is_workspace_owner) =
resolve_workspace_role_and_owner_for_auth(&chatgpt_base_url, Some(&auth)).await;
let Some(workspace_role) = workspace_role else {
return;
};
let current_auth = auth_manager.auth_cached();
if current_auth.as_ref().map(auth_identity) != Some(expected_identity) {
return;
}
let payload = account_updated_notification_for_auth(
current_auth.as_ref(),
Some(workspace_role),
is_workspace_owner,
);
outgoing
.send_server_notification(ServerNotification::AccountUpdated(payload))
.await;
});
}
impl CodexMessageProcessor {
pub(crate) fn handle_config_mutation(&self) {
self.clear_plugin_related_caches();
@@ -592,18 +498,10 @@ impl CodexMessageProcessor {
fn current_account_updated_notification(&self) -> AccountUpdatedNotification {
let auth = self.auth_manager.auth_cached();
let (workspace_role, is_workspace_owner) =
cached_workspace_role_and_owner_for_auth(auth.as_ref());
account_updated_notification_for_auth(auth.as_ref(), workspace_role, is_workspace_owner)
}
fn spawn_live_workspace_role_update(&self, auth: Option<CodexAuth>) {
spawn_live_workspace_role_update_for_auth(
self.outgoing.clone(),
self.auth_manager.clone(),
self.config.chatgpt_base_url.clone(),
auth,
);
AccountUpdatedNotification {
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
}
}
async fn load_thread(
@@ -887,10 +785,6 @@ impl CodexMessageProcessor {
self.thread_shell_command(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::ThreadAddCreditsNudgeEmail { request_id, params } => {
self.thread_add_credits_nudge_email(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::SkillsList { request_id, params } => {
self.skills_list(to_connection_request_id(request_id), params)
.await;
@@ -1210,7 +1104,6 @@ impl CodexMessageProcessor {
self.current_account_updated_notification(),
))
.await;
self.spawn_live_workspace_role_update(self.auth_manager.auth_cached());
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
@@ -1335,7 +1228,7 @@ impl CodexMessageProcessor {
replace_cloud_requirements_loader(
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url.clone(),
chatgpt_base_url,
codex_home,
);
sync_default_client_residency_requirement(
@@ -1344,27 +1237,17 @@ impl CodexMessageProcessor {
)
.await;
// Notify clients with the actual current auth mode immediately; the
// live workspace role is fetched below without delaying this update.
// Notify clients with the actual current auth mode.
let auth = auth_manager.auth_cached();
let (workspace_role, is_workspace_owner) =
cached_workspace_role_and_owner_for_auth(auth.as_ref());
let payload_v2 = account_updated_notification_for_auth(
auth.as_ref(),
workspace_role,
is_workspace_owner,
);
let payload_v2 = AccountUpdatedNotification {
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
};
outgoing_clone
.send_server_notification(ServerNotification::AccountUpdated(
payload_v2,
))
.await;
spawn_live_workspace_role_update_for_auth(
outgoing_clone.clone(),
auth_manager.clone(),
chatgpt_base_url.clone(),
auth,
);
}
// Clear the active login if it matches this attempt. It may have been replaced or cancelled.
@@ -1459,7 +1342,7 @@ impl CodexMessageProcessor {
replace_cloud_requirements_loader(
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url.clone(),
chatgpt_base_url,
codex_home,
);
sync_default_client_residency_requirement(
@@ -1469,24 +1352,15 @@ impl CodexMessageProcessor {
.await;
let auth = auth_manager.auth_cached();
let (workspace_role, is_workspace_owner) =
cached_workspace_role_and_owner_for_auth(auth.as_ref());
let payload_v2 = account_updated_notification_for_auth(
auth.as_ref(),
workspace_role,
is_workspace_owner,
);
let payload_v2 = AccountUpdatedNotification {
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
};
outgoing_clone
.send_server_notification(ServerNotification::AccountUpdated(
payload_v2,
))
.await;
spawn_live_workspace_role_update_for_auth(
outgoing_clone.clone(),
auth_manager.clone(),
chatgpt_base_url.clone(),
auth,
);
}
let mut guard = active_login.lock().await;
@@ -1635,7 +1509,6 @@ impl CodexMessageProcessor {
self.current_account_updated_notification(),
))
.await;
self.spawn_live_workspace_role_update(self.auth_manager.auth_cached());
}
async fn logout_common(&self) -> std::result::Result<Option<AuthMode>, JSONRPCErrorError> {
@@ -1673,8 +1546,6 @@ impl CodexMessageProcessor {
let payload_v2 = AccountUpdatedNotification {
auth_mode: current_auth_method,
plan_type: None,
workspace_role: None,
is_workspace_owner: None,
};
self.outgoing
.send_server_notification(ServerNotification::AccountUpdated(payload_v2))
@@ -1773,16 +1644,13 @@ impl CodexMessageProcessor {
if !requires_openai_auth {
let response = GetAccountResponse {
account: None,
workspace_role: None,
is_workspace_owner: None,
requires_openai_auth,
};
self.outgoing.send_response(request_id, response).await;
return;
}
let auth = self.auth_manager.auth_cached();
let account = match auth.as_ref() {
let account = match self.auth_manager.auth_cached() {
Some(auth) => match auth.auth_mode() {
CoreAuthMode::ApiKey => Some(Account::ApiKey {}),
CoreAuthMode::Chatgpt | CoreAuthMode::ChatgptAuthTokens => {
@@ -1809,17 +1677,12 @@ impl CodexMessageProcessor {
},
None => None,
};
let (workspace_role, is_workspace_owner) =
cached_workspace_role_and_owner_for_auth(auth.as_ref());
let response = GetAccountResponse {
account,
workspace_role,
is_workspace_owner,
requires_openai_auth,
};
self.outgoing.send_response(request_id, response).await;
self.spawn_live_workspace_role_update(auth);
}
async fn get_account_rate_limits(&self, request_id: ConnectionRequestId) {
@@ -1837,11 +1700,6 @@ impl CodexMessageProcessor {
self.outgoing.send_response(request_id, response).await;
}
Err(error) => {
tracing::warn!(
?request_id,
error = %error.message,
"account/rateLimits/read request failed"
);
self.outgoing.send_error(request_id, error).await;
}
}
@@ -3551,40 +3409,6 @@ impl CodexMessageProcessor {
}
}
async fn thread_add_credits_nudge_email(
&self,
request_id: ConnectionRequestId,
params: ThreadAddCreditsNudgeEmailParams,
) {
let ThreadAddCreditsNudgeEmailParams { thread_id } = params;
let (_, thread) = match self.load_thread(&thread_id).await {
Ok(v) => v,
Err(error) => {
self.outgoing.send_error(request_id, error).await;
return;
}
};
match self
.submit_core_op(&request_id, thread.as_ref(), Op::SendAddCreditsNudgeEmail)
.await
{
Ok(_) => {
self.outgoing
.send_response(request_id, ThreadAddCreditsNudgeEmailResponse {})
.await;
}
Err(err) => {
self.send_internal_error(
request_id,
format!("failed to request add-credits nudge email: {err}"),
)
.await;
}
}
}
async fn thread_list(&self, request_id: ConnectionRequestId, params: ThreadListParams) {
let ThreadListParams {
cursor,