mirror of
https://github.com/openai/codex.git
synced 2026-05-02 20:32:04 +03:00
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:
@@ -16,7 +16,6 @@ use chrono::Utc;
|
||||
use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot;
|
||||
use codex_protocol::protocol::RateLimitSnapshot;
|
||||
use codex_protocol::protocol::RateLimitWindow;
|
||||
use codex_protocol::protocol::SpendControlSnapshot as CoreSpendControlSnapshot;
|
||||
|
||||
const STATUS_LIMIT_BAR_SEGMENTS: usize = 20;
|
||||
const STATUS_LIMIT_BAR_FILLED: &str = "█";
|
||||
@@ -99,8 +98,6 @@ pub(crate) struct RateLimitSnapshotDisplay {
|
||||
pub secondary: Option<RateLimitWindowDisplay>,
|
||||
/// Optional credits metadata when available.
|
||||
pub credits: Option<CreditsSnapshotDisplay>,
|
||||
/// Optional spend-control metadata for usage-based workspace plans.
|
||||
pub spend_control: Option<SpendControlSnapshotDisplay>,
|
||||
}
|
||||
|
||||
/// Display-ready credits state extracted from protocol snapshots.
|
||||
@@ -114,13 +111,6 @@ pub(crate) struct CreditsSnapshotDisplay {
|
||||
pub balance: Option<String>,
|
||||
}
|
||||
|
||||
/// Display-ready spend-control state extracted from protocol snapshots.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct SpendControlSnapshotDisplay {
|
||||
/// Whether a workspace spend cap is currently blocking usage.
|
||||
pub reached: bool,
|
||||
}
|
||||
|
||||
/// Converts a protocol snapshot into UI-friendly display data.
|
||||
///
|
||||
/// Pass the timestamp from the same observation point as `snapshot`; supplying a significantly
|
||||
@@ -150,10 +140,6 @@ pub(crate) fn rate_limit_snapshot_display_for_limit(
|
||||
.as_ref()
|
||||
.map(|window| RateLimitWindowDisplay::from_window(window, captured_at)),
|
||||
credits: snapshot.credits.as_ref().map(CreditsSnapshotDisplay::from),
|
||||
spend_control: snapshot
|
||||
.spend_control
|
||||
.as_ref()
|
||||
.map(SpendControlSnapshotDisplay::from),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,14 +153,6 @@ impl From<&CoreCreditsSnapshot> for CreditsSnapshotDisplay {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&CoreSpendControlSnapshot> for SpendControlSnapshotDisplay {
|
||||
fn from(value: &CoreSpendControlSnapshot) -> Self {
|
||||
Self {
|
||||
reached: value.reached,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds display rows from a snapshot and marks stale data by capture age.
|
||||
///
|
||||
/// Callers should pass `Local::now()` for `now` at render time; using a cached timestamp can make
|
||||
@@ -197,7 +175,7 @@ pub(crate) fn compose_rate_limit_data_many(
|
||||
return StatusRateLimitData::Missing;
|
||||
}
|
||||
|
||||
let mut rows = Vec::with_capacity(snapshots.len().saturating_mul(4));
|
||||
let mut rows = Vec::with_capacity(snapshots.len().saturating_mul(3));
|
||||
let mut stale = false;
|
||||
|
||||
for snapshot in snapshots {
|
||||
@@ -285,12 +263,6 @@ pub(crate) fn compose_rate_limit_data_many(
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(spend_control) = snapshot.spend_control.as_ref()
|
||||
&& let Some(row) = spend_control_status_row(spend_control)
|
||||
{
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
if let Some(credits) = snapshot.credits.as_ref()
|
||||
&& let Some(row) = credit_status_row(credits)
|
||||
{
|
||||
@@ -350,15 +322,6 @@ fn credit_status_row(credits: &CreditsSnapshotDisplay) -> Option<StatusRateLimit
|
||||
})
|
||||
}
|
||||
|
||||
fn spend_control_status_row(
|
||||
spend_control: &SpendControlSnapshotDisplay,
|
||||
) -> Option<StatusRateLimitRow> {
|
||||
spend_control.reached.then(|| StatusRateLimitRow {
|
||||
label: "Spend cap".to_string(),
|
||||
value: StatusRateLimitValue::Text("Reached".to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
fn format_credit_balance(raw: &str) -> Option<String> {
|
||||
let trimmed = raw.trim();
|
||||
if trimmed.is_empty() {
|
||||
@@ -386,7 +349,6 @@ mod tests {
|
||||
use super::CreditsSnapshotDisplay;
|
||||
use super::RateLimitSnapshotDisplay;
|
||||
use super::RateLimitWindowDisplay;
|
||||
use super::SpendControlSnapshotDisplay;
|
||||
use super::StatusRateLimitData;
|
||||
use super::compose_rate_limit_data_many;
|
||||
use chrono::Local;
|
||||
@@ -413,7 +375,6 @@ mod tests {
|
||||
unlimited: false,
|
||||
balance: Some("25".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
};
|
||||
let other = RateLimitSnapshotDisplay {
|
||||
limit_name: "codex-other".to_string(),
|
||||
@@ -425,7 +386,6 @@ mod tests {
|
||||
unlimited: false,
|
||||
balance: Some("99".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
};
|
||||
|
||||
let rows = match compose_rate_limit_data_many(&[codex, other], now) {
|
||||
@@ -463,7 +423,6 @@ mod tests {
|
||||
window_minutes: None,
|
||||
}),
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
};
|
||||
|
||||
let rows = match compose_rate_limit_data_many(&[other], now) {
|
||||
@@ -480,28 +439,4 @@ mod tests {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_cap_reached_renders_status_row_without_windows() {
|
||||
let now = Local::now();
|
||||
let snapshot = RateLimitSnapshotDisplay {
|
||||
limit_name: "codex".to_string(),
|
||||
captured_at: now,
|
||||
primary: None,
|
||||
secondary: None,
|
||||
credits: Some(CreditsSnapshotDisplay {
|
||||
has_credits: true,
|
||||
unlimited: false,
|
||||
balance: None,
|
||||
}),
|
||||
spend_control: Some(SpendControlSnapshotDisplay { reached: true }),
|
||||
};
|
||||
|
||||
let rows = match compose_rate_limit_data_many(&[snapshot], now) {
|
||||
StatusRateLimitData::Available(rows) => rows,
|
||||
other => panic!("unexpected status: {other:?}"),
|
||||
};
|
||||
let labels: Vec<String> = rows.iter().map(|row| row.label.clone()).collect();
|
||||
assert_eq!(labels, vec!["Spend cap".to_string()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
source: tui/src/status/tests.rs
|
||||
assertion_line: 963
|
||||
expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭───────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Permissions: Custom (read-only, on-request) │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Spend cap: Reached │
|
||||
╰───────────────────────────────────────────────────────────────────────╯
|
||||
@@ -136,7 +136,6 @@ async fn status_snapshot_includes_reasoning_details() {
|
||||
resets_at: Some(reset_at_from(&captured_at, /*seconds*/ 1_200)),
|
||||
}),
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -320,7 +319,6 @@ async fn status_snapshot_includes_monthly_limit() {
|
||||
}),
|
||||
secondary: None,
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -372,7 +370,6 @@ async fn status_snapshot_shows_unlimited_credits() {
|
||||
unlimited: true,
|
||||
balance: None,
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -422,7 +419,6 @@ async fn status_snapshot_shows_positive_credits() {
|
||||
unlimited: false,
|
||||
balance: Some("12.5".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -472,7 +468,6 @@ async fn status_snapshot_hides_zero_credits() {
|
||||
unlimited: false,
|
||||
balance: Some("0".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -520,7 +515,6 @@ async fn status_snapshot_hides_when_has_no_credits_flag() {
|
||||
unlimited: true,
|
||||
balance: None,
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -626,7 +620,6 @@ async fn status_snapshot_truncates_in_narrow_terminal() {
|
||||
}),
|
||||
secondary: None,
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -740,7 +733,6 @@ async fn status_snapshot_shows_refreshing_limits_notice() {
|
||||
resets_at: Some(reset_at_from(&captured_at, /*seconds*/ 2_700)),
|
||||
}),
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -811,7 +803,6 @@ async fn status_snapshot_includes_credits_and_limits() {
|
||||
unlimited: false,
|
||||
balance: Some("37.5".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -865,69 +856,6 @@ async fn status_snapshot_shows_unavailable_limits_message() {
|
||||
primary: None,
|
||||
secondary: None,
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let captured_at = chrono::Local
|
||||
.with_ymd_and_hms(2024, 6, 7, 8, 9, 10)
|
||||
.single()
|
||||
.expect("timestamp");
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
|
||||
let model_slug = codex_core::test_support::get_model_offline(config.model.as_deref());
|
||||
let token_info = token_info_for(&model_slug, &config, &usage);
|
||||
let composite = new_status_output(
|
||||
&config,
|
||||
account_display.as_ref(),
|
||||
Some(&token_info),
|
||||
&usage,
|
||||
&None,
|
||||
/*thread_name*/ None,
|
||||
/*forked_from*/ None,
|
||||
Some(&rate_display),
|
||||
None,
|
||||
captured_at,
|
||||
&model_slug,
|
||||
/*collaboration_mode*/ None,
|
||||
/*reasoning_effort_override*/ None,
|
||||
);
|
||||
let mut rendered_lines = render_lines(&composite.display_lines(/*width*/ 80));
|
||||
if cfg!(windows) {
|
||||
for line in &mut rendered_lines {
|
||||
*line = line.replace('\\', "/");
|
||||
}
|
||||
}
|
||||
let sanitized = sanitize_directory(rendered_lines).join("\n");
|
||||
assert_snapshot!(sanitized);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn status_snapshot_shows_spend_cap_reached_message() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home).await;
|
||||
config.model = Some("gpt-5.1-codex-max".to_string());
|
||||
config.cwd = PathBuf::from("/workspace/tests").abs();
|
||||
|
||||
let account_display = test_status_account_display();
|
||||
let usage = TokenUsage {
|
||||
input_tokens: 500,
|
||||
cached_input_tokens: 0,
|
||||
output_tokens: 250,
|
||||
reasoning_output_tokens: 0,
|
||||
total_tokens: 750,
|
||||
};
|
||||
|
||||
let snapshot = RateLimitSnapshot {
|
||||
limit_id: None,
|
||||
limit_name: None,
|
||||
primary: None,
|
||||
secondary: None,
|
||||
credits: Some(CreditsSnapshot {
|
||||
has_credits: true,
|
||||
unlimited: false,
|
||||
balance: None,
|
||||
}),
|
||||
spend_control: Some(codex_protocol::protocol::SpendControlSnapshot { reached: true }),
|
||||
plan_type: None,
|
||||
};
|
||||
let captured_at = chrono::Local
|
||||
@@ -984,7 +912,6 @@ async fn status_snapshot_treats_refreshing_empty_limits_as_unavailable() {
|
||||
primary: None,
|
||||
secondary: None,
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let captured_at = chrono::Local
|
||||
@@ -1055,7 +982,6 @@ async fn status_snapshot_shows_stale_limits_message() {
|
||||
resets_at: Some(reset_at_from(&captured_at, /*seconds*/ 1_800)),
|
||||
}),
|
||||
credits: None,
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
@@ -1126,7 +1052,6 @@ async fn status_snapshot_cached_limits_hide_credits_without_flag() {
|
||||
unlimited: false,
|
||||
balance: Some("80".to_string()),
|
||||
}),
|
||||
spend_control: None,
|
||||
plan_type: None,
|
||||
};
|
||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||
|
||||
Reference in New Issue
Block a user