Show context window usage while tasks run (#4536)
## Summary - show the remaining context window percentage in `/status` alongside existing token usage details - replace the composer shortcut prompt with the context window percentage (or an unavailable message) while a task is running - update TUI snapshots to reflect the new context window line ## Testing - cargo test -p codex-tui ------ https://chatgpt.com/codex/tasks/task_i_68dc6e7397ac8321909d7daff25a396c
This commit is contained in:
@@ -29,11 +29,19 @@ use super::rate_limits::compose_rate_limit_data;
|
||||
use super::rate_limits::format_status_limit_summary;
|
||||
use super::rate_limits::render_status_limit_progress_bar;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct StatusContextWindowData {
|
||||
percent_remaining: u8,
|
||||
tokens_in_context: u64,
|
||||
window: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StatusTokenUsageData {
|
||||
total: u64,
|
||||
input: u64,
|
||||
output: u64,
|
||||
context_window: Option<StatusContextWindowData>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -52,12 +60,13 @@ struct StatusHistoryCell {
|
||||
|
||||
pub(crate) fn new_status_output(
|
||||
config: &Config,
|
||||
usage: &TokenUsage,
|
||||
total_usage: &TokenUsage,
|
||||
context_usage: Option<&TokenUsage>,
|
||||
session_id: &Option<ConversationId>,
|
||||
rate_limits: Option<&RateLimitSnapshotDisplay>,
|
||||
) -> CompositeHistoryCell {
|
||||
let command = PlainHistoryCell::new(vec!["/status".magenta().into()]);
|
||||
let card = StatusHistoryCell::new(config, usage, session_id, rate_limits);
|
||||
let card = StatusHistoryCell::new(config, total_usage, context_usage, session_id, rate_limits);
|
||||
|
||||
CompositeHistoryCell::new(vec![Box::new(command), Box::new(card)])
|
||||
}
|
||||
@@ -65,7 +74,8 @@ pub(crate) fn new_status_output(
|
||||
impl StatusHistoryCell {
|
||||
fn new(
|
||||
config: &Config,
|
||||
usage: &TokenUsage,
|
||||
total_usage: &TokenUsage,
|
||||
context_usage: Option<&TokenUsage>,
|
||||
session_id: &Option<ConversationId>,
|
||||
rate_limits: Option<&RateLimitSnapshotDisplay>,
|
||||
) -> Self {
|
||||
@@ -84,10 +94,19 @@ impl StatusHistoryCell {
|
||||
let agents_summary = compose_agents_summary(config);
|
||||
let account = compose_account_display(config);
|
||||
let session_id = session_id.as_ref().map(std::string::ToString::to_string);
|
||||
let context_window = config.model_context_window.and_then(|window| {
|
||||
context_usage.map(|usage| StatusContextWindowData {
|
||||
percent_remaining: usage.percent_of_context_window_remaining(window),
|
||||
tokens_in_context: usage.tokens_in_context_window(),
|
||||
window,
|
||||
})
|
||||
});
|
||||
|
||||
let token_usage = StatusTokenUsageData {
|
||||
total: usage.blended_total(),
|
||||
input: usage.non_cached_input(),
|
||||
output: usage.output_tokens,
|
||||
total: total_usage.blended_total(),
|
||||
input: total_usage.non_cached_input(),
|
||||
output: total_usage.output_tokens,
|
||||
context_window,
|
||||
};
|
||||
let rate_limits = compose_rate_limit_data(rate_limits);
|
||||
|
||||
@@ -123,6 +142,22 @@ impl StatusHistoryCell {
|
||||
]
|
||||
}
|
||||
|
||||
fn context_window_spans(&self) -> Option<Vec<Span<'static>>> {
|
||||
let context = self.token_usage.context_window.as_ref()?;
|
||||
let percent = context.percent_remaining;
|
||||
let used_fmt = format_tokens_compact(context.tokens_in_context);
|
||||
let window_fmt = format_tokens_compact(context.window);
|
||||
|
||||
Some(vec![
|
||||
Span::from(format!("{percent}% left")),
|
||||
Span::from(" (").dim(),
|
||||
Span::from(used_fmt).dim(),
|
||||
Span::from(" / ").dim(),
|
||||
Span::from(window_fmt).dim(),
|
||||
Span::from(")").dim(),
|
||||
])
|
||||
}
|
||||
|
||||
fn rate_limit_lines(
|
||||
&self,
|
||||
available_inner_width: usize,
|
||||
@@ -235,6 +270,9 @@ impl HistoryCell for StatusHistoryCell {
|
||||
push_label(&mut labels, &mut seen, "Session");
|
||||
}
|
||||
push_label(&mut labels, &mut seen, "Token usage");
|
||||
if self.token_usage.context_window.is_some() {
|
||||
push_label(&mut labels, &mut seen, "Context window");
|
||||
}
|
||||
self.collect_rate_limit_labels(&mut seen, &mut labels);
|
||||
|
||||
let formatter = FieldFormatter::from_labels(labels.iter().map(String::as_str));
|
||||
@@ -266,6 +304,10 @@ impl HistoryCell for StatusHistoryCell {
|
||||
lines.push(Line::from(Vec::<Span<'static>>::new()));
|
||||
lines.push(formatter.line("Token usage", self.token_usage_spans()));
|
||||
|
||||
if let Some(spans) = self.context_window_spans() {
|
||||
lines.push(formatter.line("Context window", spans));
|
||||
}
|
||||
|
||||
lines.extend(self.rate_limit_lines(available_inner_width, &formatter));
|
||||
|
||||
let content_width = lines.iter().map(line_display_width).max().unwrap_or(0);
|
||||
|
||||
Reference in New Issue
Block a user