Add limits to /status (#4053)
Add limits to status <img width="579" height="430" alt="image" src="https://github.com/user-attachments/assets/d3794d92-ffca-47be-8011-b4452223cc89" />
This commit is contained in:
@@ -1368,6 +1368,7 @@ impl ChatWidget {
|
|||||||
&self.config,
|
&self.config,
|
||||||
usage_ref,
|
usage_ref,
|
||||||
&self.conversation_id,
|
&self.conversation_id,
|
||||||
|
self.rate_limit_snapshot.as_ref(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ use std::time::Instant;
|
|||||||
use tracing::error;
|
use tracing::error;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
const STATUS_LIMIT_BAR_SEGMENTS: usize = 20;
|
||||||
|
const STATUS_LIMIT_BAR_FILLED: &str = "█";
|
||||||
|
const STATUS_LIMIT_BAR_EMPTY: &str = " ";
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct CommandOutput {
|
pub(crate) struct CommandOutput {
|
||||||
pub(crate) exit_code: i32,
|
pub(crate) exit_code: i32,
|
||||||
@@ -1123,6 +1127,7 @@ pub(crate) fn new_status_output(
|
|||||||
config: &Config,
|
config: &Config,
|
||||||
usage: &TokenUsage,
|
usage: &TokenUsage,
|
||||||
session_id: &Option<ConversationId>,
|
session_id: &Option<ConversationId>,
|
||||||
|
rate_limits: Option<&RateLimitSnapshotEvent>,
|
||||||
) -> PlainHistoryCell {
|
) -> PlainHistoryCell {
|
||||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||||
lines.push("/status".magenta().into());
|
lines.push("/status".magenta().into());
|
||||||
@@ -1283,6 +1288,9 @@ pub(crate) fn new_status_output(
|
|||||||
format_with_separators(usage.blended_total()).into(),
|
format_with_separators(usage.blended_total()).into(),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
lines.push("".into());
|
||||||
|
lines.extend(build_status_limit_lines(rate_limits));
|
||||||
|
|
||||||
PlainHistoryCell { lines }
|
PlainHistoryCell { lines }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1640,6 +1648,62 @@ fn format_mcp_invocation<'a>(invocation: McpInvocation) -> Line<'a> {
|
|||||||
invocation_spans.into()
|
invocation_spans.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_status_limit_lines(snapshot: Option<&RateLimitSnapshotEvent>) -> Vec<Line<'static>> {
|
||||||
|
let mut lines: Vec<Line<'static>> =
|
||||||
|
vec![vec![padded_emoji("⏱️").into(), "Usage Limits".bold()].into()];
|
||||||
|
|
||||||
|
match snapshot {
|
||||||
|
Some(snapshot) => {
|
||||||
|
let rows = [
|
||||||
|
("5h limit".to_string(), snapshot.primary_used_percent),
|
||||||
|
("Weekly limit".to_string(), snapshot.weekly_used_percent),
|
||||||
|
];
|
||||||
|
let label_width = rows
|
||||||
|
.iter()
|
||||||
|
.map(|(label, _)| UnicodeWidthStr::width(label.as_str()))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
for (label, percent) in rows {
|
||||||
|
lines.push(build_status_limit_line(&label, percent, label_width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => lines.push(" • Rate limit data not available yet.".dim().into()),
|
||||||
|
}
|
||||||
|
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_status_limit_line(label: &str, percent_used: f64, label_width: usize) -> Line<'static> {
|
||||||
|
let clamped_percent = percent_used.clamp(0.0, 100.0);
|
||||||
|
let progress = render_status_limit_progress_bar(clamped_percent);
|
||||||
|
let summary = format_status_limit_summary(clamped_percent);
|
||||||
|
|
||||||
|
let mut spans: Vec<Span<'static>> = Vec::with_capacity(5);
|
||||||
|
let padded_label = format!("{label:<label_width$}");
|
||||||
|
spans.push(format!(" • {padded_label}: ").into());
|
||||||
|
spans.push(progress.into());
|
||||||
|
spans.push(" ".into());
|
||||||
|
spans.push(summary.into());
|
||||||
|
|
||||||
|
Line::from(spans)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_status_limit_progress_bar(percent_used: f64) -> String {
|
||||||
|
let ratio = (percent_used / 100.0).clamp(0.0, 1.0);
|
||||||
|
let filled = (ratio * STATUS_LIMIT_BAR_SEGMENTS as f64).round() as usize;
|
||||||
|
let filled = filled.min(STATUS_LIMIT_BAR_SEGMENTS);
|
||||||
|
let empty = STATUS_LIMIT_BAR_SEGMENTS.saturating_sub(filled);
|
||||||
|
format!(
|
||||||
|
"[{}{}]",
|
||||||
|
STATUS_LIMIT_BAR_FILLED.repeat(filled),
|
||||||
|
STATUS_LIMIT_BAR_EMPTY.repeat(empty)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_status_limit_summary(percent_used: f64) -> String {
|
||||||
|
format!("{percent_used:.0}% used")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user