/status followup (#4304)

- Render `send a message to load usage data` in the beginning of the
session
- Render `data not available yet` if received no rate limits 
- nit case
- Deleted stall snapshots that were moved to
`codex-rs/tui/src/status/snapshots`
This commit is contained in:
Ahmed Ibrahim
2025-09-26 11:16:54 -07:00
committed by GitHub
parent d3f6f6629b
commit 1fba99ed85
12 changed files with 82 additions and 70 deletions

View File

@@ -559,10 +559,6 @@ fn parse_rate_limit_snapshot(headers: &HeaderMap) -> Option<RateLimitSnapshot> {
"x-codex-secondary-reset-after-seconds",
);
if primary.is_none() && secondary.is_none() {
return None;
}
Some(RateLimitSnapshot { primary, secondary })
}

View File

@@ -1,19 +0,0 @@
---
source: tui/src/status.rs
expression: sanitized
---
/status
╭──────────────────────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.0.0) │
│ │
│ Model : gpt-5-codex (reasoning high, summaries detailed) │
│ Directory : /workspace/tests │
│ Approval : on-request │
│ Sandbox : workspace-write │
│ Agents.md : <none> │
│ │
│ Token Usage : 1.9K total (1K input + 900 output) │
│ 5h limit : [███████████████░░░░░] 72% used · resets 03:14 │
│ Weekly limit : [█████████░░░░░░░░░░░] 45% used · resets 03:24 │
╰──────────────────────────────────────────────────────────────────╯

View File

@@ -1,19 +0,0 @@
---
source: tui/src/status.rs
expression: sanitized
---
/status
╭────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.0.0) │
│ │
│ Model : gpt-5-codex (reasoning high │
│ Directory : /workspace/tests │
│ Approval : on-request │
│ Sandbox : read-only │
│ Agents.md : <none> │
│ │
│ Token Usage : 1.9K total (1K input + 900 │
│ 5h limit : [███████████████░░░░░] 72% │
│ · resets 03:14 │
╰────────────────────────────────────────────╯

View File

@@ -23,7 +23,6 @@ use super::helpers::compose_agents_summary;
use super::helpers::compose_model_display;
use super::helpers::format_directory_display;
use super::helpers::format_tokens_compact;
use super::rate_limits::RESET_BULLET;
use super::rate_limits::RateLimitSnapshotDisplay;
use super::rate_limits::StatusRateLimitData;
use super::rate_limits::compose_rate_limit_data;
@@ -149,8 +148,7 @@ impl StatusHistoryCell {
let base_line = Line::from(base_spans.clone());
if let Some(resets_at) = row.resets_at.as_ref() {
let resets_span =
Span::from(format!("{RESET_BULLET} resets {resets_at}")).dim();
let resets_span = Span::from(format!("(resets {resets_at})")).dim();
let mut inline_spans = base_spans.clone();
inline_spans.push(Span::from(" ").dim());
inline_spans.push(resets_span.clone());
@@ -171,7 +169,10 @@ impl StatusHistoryCell {
lines
}
StatusRateLimitData::Missing => {
vec![formatter.line("Limits", vec![Span::from("data not available yet").dim()])]
vec![formatter.line(
"Limits",
vec![Span::from("send a message to load usage data").dim()],
)]
}
}
}
@@ -233,7 +234,7 @@ impl HistoryCell for StatusHistoryCell {
if self.session_id.is_some() {
push_label(&mut labels, &mut seen, "Session");
}
push_label(&mut labels, &mut seen, "Token Usage");
push_label(&mut labels, &mut seen, "Token usage");
self.collect_rate_limit_labels(&mut seen, &mut labels);
let formatter = FieldFormatter::from_labels(labels.iter().map(String::as_str));
@@ -263,7 +264,7 @@ impl HistoryCell for StatusHistoryCell {
}
lines.push(Line::from(Vec::<Span<'static>>::new()));
lines.push(formatter.line("Token Usage", self.token_usage_spans()));
lines.push(formatter.line("Token usage", self.token_usage_spans()));
lines.extend(self.rate_limit_lines(available_inner_width, &formatter));

View File

@@ -162,7 +162,7 @@ pub(crate) fn format_reset_timestamp(dt: DateTime<Local>, captured_at: DateTime<
if dt.date_naive() == captured_at.date_naive() {
time
} else {
format!("{} ({time})", dt.format("%-d %b"))
format!("{time} on {}", dt.format("%-d %b"))
}
}

View File

@@ -11,7 +11,6 @@ use std::convert::TryFrom;
const STATUS_LIMIT_BAR_SEGMENTS: usize = 20;
const STATUS_LIMIT_BAR_FILLED: &str = "";
const STATUS_LIMIT_BAR_EMPTY: &str = "";
pub(crate) const RESET_BULLET: &str = "·";
#[derive(Debug, Clone)]
pub(crate) struct StatusRateLimitRow {
@@ -105,7 +104,7 @@ pub(crate) fn compose_rate_limit_data(
}
if rows.is_empty() {
StatusRateLimitData::Missing
StatusRateLimitData::Available(vec![])
} else {
StatusRateLimitData::Available(rows)
}

View File

@@ -4,15 +4,15 @@ expression: sanitized
---
/status
╭──────────────────────────────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.0.0) │
│ │
│ Model: gpt-5-codex (reasoning none, summaries auto) │
│ Directory: [[workspace]] │
│ Approval: on-request │
│ Sandbox: read-only │
│ Agents.md: <none> │
│ │
│ Token Usage: 1.2K total (800 input + 400 output) │
│ Monthly limit: [██░░░░░░░░░░░░░░░░░░] 12% used · resets 7 May (07:08) │
╰──────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────
│ >_ OpenAI Codex (v0.0.0)
│ Model: gpt-5-codex (reasoning none, summaries auto)
│ Directory: [[workspace]]
│ Approval: on-request
│ Sandbox: read-only
│ Agents.md: <none>
│ Token usage: 1.2K total (800 input + 400 output)
│ Monthly limit: [██░░░░░░░░░░░░░░░░░░] 12% used (resets 07:08 on 7 May) │
╰──────────────────────────────────────────────────────────────────────────

View File

@@ -13,7 +13,7 @@ expression: sanitized
│ Sandbox: workspace-write │
│ Agents.md: <none> │
│ │
│ Token Usage: 1.9K total (1K input + 900 output) │
│ 5h limit: [███████████████░░░░░] 72% used · resets 03:14 │
│ Weekly limit: [█████████░░░░░░░░░░░] 45% used · resets 03:24 │
│ Token usage: 1.9K total (1K input + 900 output) │
│ 5h limit: [███████████████░░░░░] 72% used (resets 03:14)
│ Weekly limit: [█████████░░░░░░░░░░░] 45% used (resets 03:24)
╰───────────────────────────────────────────────────────────────────╯

View File

@@ -0,0 +1,18 @@
---
source: tui/src/status/tests.rs
expression: sanitized
---
/status
╭──────────────────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.0.0) │
│ │
│ Model: gpt-5-codex (reasoning none, summaries auto) │
│ Directory: [[workspace]] │
│ Approval: on-request │
│ Sandbox: read-only │
│ Agents.md: <none> │
│ │
│ Token usage: 750 total (500 input + 250 output) │
│ Limits: data not available yet │
╰──────────────────────────────────────────────────────────────╯

View File

@@ -13,6 +13,6 @@ expression: sanitized
│ Sandbox: read-only │
│ Agents.md: <none> │
│ │
│ Token Usage: 750 total (500 input + 250 output) │
│ Limits: data not available yet
│ Token usage: 750 total (500 input + 250 output) │
│ Limits: send a message to load usage data
╰──────────────────────────────────────────────────────────────╯

View File

@@ -13,7 +13,7 @@ expression: sanitized
│ Sandbox: read-only │
│ Agents.md: <none> │
│ │
│ Token Usage: 1.9K total (1K input + 90 │
│ Token usage: 1.9K total (1K input + 90 │
│ 5h limit: [███████████████░░░░░] 72% │
· resets 03:14 │
(resets 03:14)
╰────────────────────────────────────────────╯

View File

@@ -248,3 +248,39 @@ fn status_snapshot_shows_missing_limits_message() {
let sanitized = sanitize_directory(rendered_lines).join("\n");
assert_snapshot!(sanitized);
}
#[test]
fn status_snapshot_shows_empty_limits_message() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home);
config.model = "gpt-5-codex".to_string();
config.cwd = PathBuf::from("/workspace/tests");
let usage = TokenUsage {
input_tokens: 500,
cached_input_tokens: 0,
output_tokens: 250,
reasoning_output_tokens: 0,
total_tokens: 750,
};
let snapshot = RateLimitSnapshot {
primary: None,
secondary: 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 composite = new_status_output(&config, &usage, &None, Some(&rate_display));
let mut rendered_lines = render_lines(&composite.display_lines(80));
if cfg!(windows) {
for line in &mut rendered_lines {
*line = line.replace('\\', "/");
}
}
let sanitized = sanitize_directory(rendered_lines).join("\n");
assert_snapshot!(sanitized);
}