diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index b6708647868214d3ca02a2952ce718defe6ab557..7caeb687bebb32083c2647a2bc0d359b36e03b58 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -3402,29 +3402,14 @@ impl ThreadView { fn render_token_usage(&self, cx: &mut Context) -> Option { let thread = self.thread.read(cx); let usage = thread.token_usage()?; - let is_generating = thread.status() != ThreadStatus::Idle; let show_split = self.supports_split_token_display(cx); - let separator_color = Color::Custom(cx.theme().colors().text_muted.opacity(0.5)); - let token_label = |text: String, animation_id: &'static str| { - Label::new(text) - .size(LabelSize::Small) - .color(Color::Muted) - .map(|label| { - if is_generating { - label - .with_animation( - animation_id, - Animation::new(Duration::from_secs(2)) - .repeat() - .with_easing(pulsating_between(0.3, 0.8)), - |label, delta| label.alpha(delta), - ) - .into_any() - } else { - label.into_any_element() - } - }) + let progress_color = |ratio: f32| -> Hsla { + if ratio >= 0.85 { + cx.theme().status().warning + } else { + cx.theme().colors().text_muted + } }; let used = crate::text_thread_editor::humanize_token_count(usage.used_tokens); @@ -3439,6 +3424,10 @@ impl ThreadView { } else { 0.0 }; + + let ring_size = px(16.0); + let stroke_width = px(2.); + let percentage = format!("{}%", (progress_ratio * 100.0).round() as u32); let tooltip_separator_color = Color::Custom(cx.theme().colors().text_disabled.opacity(0.6)); @@ -3478,8 +3467,6 @@ impl ThreadView { let output_max_label = crate::text_thread_editor::humanize_token_count(max_output_tokens); let build_tooltip = { - let input_max_label = input_max_label.clone(); - let output_max_label = output_max_label.clone(); move |_window: &mut Window, cx: &mut App| { let percentage = percentage.clone(); let used = used.clone(); @@ -3511,17 +3498,26 @@ impl ThreadView { }; if show_split { - let input = crate::text_thread_editor::humanize_token_count(usage.input_tokens); - let input_max = input_max_label; - let output = crate::text_thread_editor::humanize_token_count(usage.output_tokens); - let output_max = output_max_label; + let input_max_raw = usage.max_tokens.saturating_sub(max_output_tokens); + let output_max_raw = max_output_tokens; + + let input_ratio = if input_max_raw > 0 { + usage.input_tokens as f32 / input_max_raw as f32 + } else { + 0.0 + }; + let output_ratio = if output_max_raw > 0 { + usage.output_tokens as f32 / output_max_raw as f32 + } else { + 0.0 + }; Some( h_flex() .id("split_token_usage") .flex_shrink_0() - .gap_1() - .mr_1p5() + .gap_1p5() + .mr_1() .child( h_flex() .gap_0p5() @@ -3530,16 +3526,15 @@ impl ThreadView { .size(IconSize::XSmall) .color(Color::Muted), ) - .child(token_label(input, "input-tokens-label")) - .child( - Label::new("/") - .size(LabelSize::Small) - .color(separator_color), - ) .child( - Label::new(input_max) - .size(LabelSize::Small) - .color(Color::Muted), + CircularProgress::new( + usage.input_tokens as f32, + input_max_raw as f32, + ring_size, + cx, + ) + .stroke_width(stroke_width) + .progress_color(progress_color(input_ratio)), ), ) .child( @@ -3550,28 +3545,21 @@ impl ThreadView { .size(IconSize::XSmall) .color(Color::Muted), ) - .child(token_label(output, "output-tokens-label")) .child( - Label::new("/") - .size(LabelSize::Small) - .color(separator_color), - ) - .child( - Label::new(output_max) - .size(LabelSize::Small) - .color(Color::Muted), + CircularProgress::new( + usage.output_tokens as f32, + output_max_raw as f32, + ring_size, + cx, + ) + .stroke_width(stroke_width) + .progress_color(progress_color(output_ratio)), ), ) .hoverable_tooltip(build_tooltip) .into_any_element(), ) } else { - let progress_color = if progress_ratio >= 0.85 { - cx.theme().status().warning - } else { - cx.theme().colors().text_muted - }; - Some( h_flex() .id("circular_progress_tokens") @@ -3581,11 +3569,11 @@ impl ThreadView { CircularProgress::new( usage.used_tokens as f32, usage.max_tokens as f32, - px(16.0), + ring_size, cx, ) - .stroke_width(px(2.)) - .progress_color(progress_color), + .stroke_width(stroke_width) + .progress_color(progress_color(progress_ratio)), ) .hoverable_tooltip(build_tooltip) .into_any_element(), @@ -4173,13 +4161,13 @@ impl Render for TokenUsageTooltip { ui::tooltip_container(cx, move |container, cx| { container .min_w_40() + .child( + Label::new("Context") + .color(Color::Muted) + .size(LabelSize::Small), + ) .when(!show_split, |this| { this.child( - Label::new("Context") - .color(Color::Muted) - .size(LabelSize::Small), - ) - .child( h_flex() .gap_0p5() .child(Label::new(percentage.clone()))