feat(tui): warn high effort rate use (#5035)

Highlight that selecting a high reasoning level will hit Plus plan rate
limits faster.
This commit is contained in:
joshka-oai
2025-10-15 14:57:05 -07:00
committed by GitHub
parent 17550fee9e
commit 18d00e36b9
3 changed files with 27 additions and 6 deletions

View File

@@ -37,6 +37,7 @@ pub(crate) struct SelectionItem {
pub name: String, pub name: String,
pub display_shortcut: Option<KeyBinding>, pub display_shortcut: Option<KeyBinding>,
pub description: Option<String>, pub description: Option<String>,
pub selected_description: Option<String>,
pub is_current: bool, pub is_current: bool,
pub actions: Vec<SelectionAction>, pub actions: Vec<SelectionAction>,
pub dismiss_on_select: bool, pub dismiss_on_select: bool,
@@ -193,12 +194,16 @@ impl ListSelectionView {
} else { } else {
format!("{prefix} {n}. {name_with_marker}") format!("{prefix} {n}. {name_with_marker}")
}; };
let description = is_selected
.then(|| item.selected_description.clone())
.flatten()
.or_else(|| item.description.clone());
GenericDisplayRow { GenericDisplayRow {
name: display_name, name: display_name,
display_shortcut: item.display_shortcut, display_shortcut: item.display_shortcut,
match_indices: None, match_indices: None,
is_current: item.is_current, is_current: item.is_current,
description: item.description.clone(), description,
} }
}) })
}) })

View File

@@ -53,6 +53,8 @@ use ratatui::buffer::Buffer;
use ratatui::layout::Constraint; use ratatui::layout::Constraint;
use ratatui::layout::Layout; use ratatui::layout::Layout;
use ratatui::layout::Rect; use ratatui::layout::Rect;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::Widget; use ratatui::widgets::Widget;
use ratatui::widgets::WidgetRef; use ratatui::widgets::WidgetRef;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
@@ -81,6 +83,7 @@ use crate::history_cell::AgentMessageCell;
use crate::history_cell::HistoryCell; use crate::history_cell::HistoryCell;
use crate::history_cell::McpToolCallCell; use crate::history_cell::McpToolCallCell;
use crate::markdown::append_markdown; use crate::markdown::append_markdown;
use crate::render::renderable::ColumnRenderable;
use crate::slash_command::SlashCommand; use crate::slash_command::SlashCommand;
use crate::status::RateLimitSnapshotDisplay; use crate::status::RateLimitSnapshotDisplay;
use crate::text_formatting::truncate_text; use crate::text_formatting::truncate_text;
@@ -1718,7 +1721,6 @@ impl ChatWidget {
} else { } else {
default_choice default_choice
}; };
let mut items: Vec<SelectionItem> = Vec::new(); let mut items: Vec<SelectionItem> = Vec::new();
for choice in choices.iter() { for choice in choices.iter() {
let effort = choice.display; let effort = choice.display;
@@ -1741,6 +1743,14 @@ impl ChatWidget {
.map(|preset| preset.description.to_string()) .map(|preset| preset.description.to_string())
}); });
let warning = "⚠ High reasoning effort can quickly consume Plus plan rate limits.";
let show_warning = model_slug == "gpt-5-codex" && effort == ReasoningEffortConfig::High;
let selected_description = show_warning.then(|| {
description
.as_ref()
.map_or(warning.to_string(), |d| format!("{d}\n{warning}"))
});
let model_for_action = model_slug.clone(); let model_for_action = model_slug.clone();
let effort_for_action = choice.stored; let effort_for_action = choice.stored;
let actions: Vec<SelectionAction> = vec![Box::new(move |tx| { let actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
@@ -1770,6 +1780,7 @@ impl ChatWidget {
items.push(SelectionItem { items.push(SelectionItem {
name: effort_label, name: effort_label,
description, description,
selected_description,
is_current: is_current_model && choice.stored == highlight_choice, is_current: is_current_model && choice.stored == highlight_choice,
actions, actions,
dismiss_on_select: true, dismiss_on_select: true,
@@ -1777,9 +1788,13 @@ impl ChatWidget {
}); });
} }
let mut header = ColumnRenderable::new();
header.push(Line::from(
format!("Select Reasoning Level for {model_slug}").bold(),
));
self.bottom_pane.show_selection_view(SelectionViewParams { self.bottom_pane.show_selection_view(SelectionViewParams {
title: Some("Select Reasoning Level".to_string()), header: Box::new(header),
subtitle: Some(format!("Reasoning for model {model_slug}")),
footer_hint: Some(standard_popup_hint_line()), footer_hint: Some(standard_popup_hint_line()),
items, items,
..Default::default() ..Default::default()

View File

@@ -2,12 +2,13 @@
source: tui/src/chatwidget/tests.rs source: tui/src/chatwidget/tests.rs
expression: popup expression: popup
--- ---
Select Reasoning Level Select Reasoning Level for gpt-5-codex
Reasoning for model gpt-5-codex
1. Low Fastest responses with limited reasoning 1. Low Fastest responses with limited reasoning
2. Medium (default) Dynamically adjusts reasoning based on the task 2. Medium (default) Dynamically adjusts reasoning based on the task
3. High (current) Maximizes reasoning depth for complex or ambiguous 3. High (current) Maximizes reasoning depth for complex or ambiguous
problems problems
⚠ High reasoning effort can quickly consume Plus plan
rate limits.
Press enter to confirm or esc to go back Press enter to confirm or esc to go back