Reflect token limit errors and warnings in the assistant panel Send button style (#15529)

When used token count is below 80%, the Send button is displayed as
usual: no tooltip, regular style:


![image](https://github.com/user-attachments/assets/06198869-c49e-4231-b0cb-53b8f678c547)

When it exceeds 80% but below the `max_tokens` threshold, the button
starts to show as a warning, with the corresponding tooltip:

![warning](https://github.com/user-attachments/assets/83b02059-9610-4af7-97c6-9bca14364511)

When it is over the `max_token` threshold, the button starts to show as
an error, with another tooltip:

![error](https://github.com/user-attachments/assets/380d426a-cda9-4479-83e0-e018771291b6)

The buttons are not blocked in any case, in case the token calculation
is wrong, to allow using the assistant panel nonetheless.


Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-07-31 14:37:39 +03:00 committed by GitHub
parent 380a19fcf2
commit a31dba9fc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -58,6 +58,7 @@ use std::{
time::Duration,
};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use ui::TintColor;
use ui::{
prelude::*,
utils::{format_distance_from_now, DateTimeType},
@ -2320,8 +2321,34 @@ impl ContextEditor {
},
None => "Send",
};
let (style, tooltip) = match token_state(&self.context, cx) {
Some(TokenState::NoTokensLeft { .. }) => (
ButtonStyle::Tinted(TintColor::Negative),
Some(Tooltip::text("Token limit reached", cx)),
),
Some(TokenState::HasMoreTokens {
over_warn_threshold,
..
}) => {
let (style, tooltip) = if over_warn_threshold {
(
ButtonStyle::Tinted(TintColor::Warning),
Some(Tooltip::text("Token limit is close to exhaustion", cx)),
)
} else {
(ButtonStyle::Filled, None)
};
(style, tooltip)
}
None => (ButtonStyle::Filled, None),
};
ButtonLike::new("send_button")
.style(ButtonStyle::Filled)
.style(style)
.when_some(tooltip, |button, tooltip| {
button.tooltip(move |_| tooltip.clone())
})
.layer(ElevationIndex::ModalSurface)
.children(
KeyBinding::for_action_in(&Assist, &focus_handle, cx)
@ -2726,25 +2753,30 @@ impl ContextEditorToolbarItem {
}
fn render_remaining_tokens(&self, cx: &mut ViewContext<Self>) -> Option<impl IntoElement> {
let model = LanguageModelRegistry::read_global(cx).active_model()?;
let context = &self
.active_context_editor
.as_ref()?
.upgrade()?
.read(cx)
.context;
let token_count = context.read(cx).token_count()?;
let max_token_count = model.max_token_count();
let remaining_tokens = max_token_count as isize - token_count as isize;
let token_count_color = if remaining_tokens <= 0 {
Color::Error
} else if token_count as f32 / max_token_count as f32 >= 0.8 {
Color::Warning
} else {
Color::Muted
let (token_count_color, token_count, max_token_count) = match token_state(context, cx)? {
TokenState::NoTokensLeft {
max_token_count,
token_count,
} => (Color::Error, token_count, max_token_count),
TokenState::HasMoreTokens {
max_token_count,
token_count,
over_warn_threshold,
} => {
let color = if over_warn_threshold {
Color::Warning
} else {
Color::Muted
};
(color, token_count, max_token_count)
}
};
Some(
h_flex()
.gap_0p5()
@ -3077,3 +3109,40 @@ fn slash_command_error_block_renderer(message: String) -> RenderBlock {
.into_any()
})
}
enum TokenState {
NoTokensLeft {
max_token_count: usize,
token_count: usize,
},
HasMoreTokens {
max_token_count: usize,
token_count: usize,
over_warn_threshold: bool,
},
}
fn token_state(context: &Model<Context>, cx: &AppContext) -> Option<TokenState> {
const WARNING_TOKEN_THRESHOLD: f32 = 0.8;
let model = LanguageModelRegistry::read_global(cx).active_model()?;
let token_count = context.read(cx).token_count()?;
let max_token_count = model.max_token_count();
let remaining_tokens = max_token_count as isize - token_count as isize;
let token_state = if remaining_tokens <= 0 {
TokenState::NoTokensLeft {
max_token_count,
token_count,
}
} else {
let over_warn_threshold =
token_count as f32 / max_token_count as f32 >= WARNING_TOKEN_THRESHOLD;
TokenState::HasMoreTokens {
max_token_count,
token_count,
over_warn_threshold,
}
};
Some(token_state)
}