fix: exclude sysprompt etc from context left % (#2446)
- Prevents the % left indicator from immediately decrementing to ~97%. - Tested by prompting "hi" and noting it only decremented to 99%. And by adding a bunch of debug logs and observing numbers.
This commit is contained in:
@@ -508,6 +508,33 @@ impl TokenUsage {
|
||||
self.total_tokens
|
||||
.saturating_sub(self.reasoning_output_tokens.unwrap_or(0))
|
||||
}
|
||||
|
||||
/// Estimate the remaining user-controllable percentage of the model's context window.
|
||||
///
|
||||
/// `context_window` is the total size of the model's context window.
|
||||
/// `baseline_used_tokens` should capture tokens that are always present in
|
||||
/// the context (e.g., system prompt and fixed tool instructions) so that
|
||||
/// the percentage reflects the portion the user can influence.
|
||||
///
|
||||
/// This normalizes both the numerator and denominator by subtracting the
|
||||
/// baseline, so immediately after the first prompt the UI shows 100% left
|
||||
/// and trends toward 0% as the user fills the effective window.
|
||||
pub fn percent_of_context_window_remaining(
|
||||
&self,
|
||||
context_window: u64,
|
||||
baseline_used_tokens: u64,
|
||||
) -> u8 {
|
||||
if context_window <= baseline_used_tokens {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let effective_window = context_window - baseline_used_tokens;
|
||||
let used = self
|
||||
.tokens_in_context_window()
|
||||
.saturating_sub(baseline_used_tokens);
|
||||
let remaining = effective_window.saturating_sub(used);
|
||||
((remaining as f32 / effective_window as f32) * 100.0).clamp(0.0, 100.0) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
|
||||
@@ -45,6 +45,15 @@ struct TokenUsageInfo {
|
||||
total_token_usage: TokenUsage,
|
||||
last_token_usage: TokenUsage,
|
||||
model_context_window: Option<u64>,
|
||||
/// Baseline token count present in the context before the user's first
|
||||
/// message content is considered. This is used to normalize the
|
||||
/// "context left" percentage so it reflects the portion the user can
|
||||
/// influence rather than fixed prompt overhead (system prompt, tool
|
||||
/// instructions, etc.).
|
||||
///
|
||||
/// Preferred source is `cached_input_tokens` from the first turn (when
|
||||
/// available), otherwise we fall back to 0.
|
||||
initial_prompt_tokens: u64,
|
||||
}
|
||||
|
||||
pub(crate) struct ChatComposer {
|
||||
@@ -134,10 +143,17 @@ impl ChatComposer {
|
||||
last_token_usage: TokenUsage,
|
||||
model_context_window: Option<u64>,
|
||||
) {
|
||||
let initial_prompt_tokens = self
|
||||
.token_usage_info
|
||||
.as_ref()
|
||||
.map(|info| info.initial_prompt_tokens)
|
||||
.unwrap_or_else(|| last_token_usage.cached_input_tokens.unwrap_or(0));
|
||||
|
||||
self.token_usage_info = Some(TokenUsageInfo {
|
||||
total_token_usage,
|
||||
last_token_usage,
|
||||
model_context_window,
|
||||
initial_prompt_tokens,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -673,11 +689,10 @@ impl WidgetRef for &ChatComposer {
|
||||
let last_token_usage = &token_usage_info.last_token_usage;
|
||||
if let Some(context_window) = token_usage_info.model_context_window {
|
||||
let percent_remaining: u8 = if context_window > 0 {
|
||||
let percent = 100.0
|
||||
- (last_token_usage.tokens_in_context_window() as f32
|
||||
/ context_window as f32
|
||||
* 100.0);
|
||||
percent.clamp(0.0, 100.0) as u8
|
||||
last_token_usage.percent_of_context_window_remaining(
|
||||
context_window,
|
||||
token_usage_info.initial_prompt_tokens,
|
||||
)
|
||||
} else {
|
||||
100
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user