agent_ui: Make "waiting confirmation" state more apparent (#41998)

This PR changes the loading/generating indicator when in the "waiting
for tool call confirmation" state so that's a bit more visible and
discernible as needing your attention, as opposed to a regular
generating state.

<img width="400" alt="Screenshot 2025-11-05 at 10  46@2x"
src="https://github.com/user-attachments/assets/88adbf97-20fb-49c4-9c77-b0a3a22aa14e"
/>

Release Notes:

- agent: Improved the "waiting for confirmation" state visibility so
that you more rapidly know the agent is waiting for you to act.
This commit is contained in:
Danilo Leal
2025-11-05 11:45:44 -03:00
committed by GitHub
parent c8ada5b1ae
commit 0f5a63a9b0
3 changed files with 83 additions and 41 deletions
+24 -33
View File
@@ -1,5 +1,5 @@
use crate::prelude::*;
use gpui::{Animation, AnimationExt, FontWeight, pulsating_between};
use gpui::{Animation, AnimationExt, FontWeight};
use std::time::Duration;
#[derive(IntoElement)]
@@ -84,38 +84,29 @@ impl RenderOnce for LoadingLabel {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let text = self.text.clone();
self.base
.color(Color::Muted)
.with_animations(
"loading_label",
vec![
Animation::new(Duration::from_secs(1)),
Animation::new(Duration::from_secs(1)).repeat(),
],
move |mut label, animation_ix, delta| {
match animation_ix {
0 => {
let chars_to_show = (delta * text.len() as f32).ceil() as usize;
let text = SharedString::from(text[0..chars_to_show].to_string());
label.set_text(text);
}
1 => match delta {
d if d < 0.25 => label.set_text(text.clone()),
d if d < 0.5 => label.set_text(format!("{}.", text)),
d if d < 0.75 => label.set_text(format!("{}..", text)),
_ => label.set_text(format!("{}...", text)),
},
_ => {}
self.base.color(Color::Muted).with_animations(
"loading_label",
vec![
Animation::new(Duration::from_secs(1)),
Animation::new(Duration::from_secs(1)).repeat(),
],
move |mut label, animation_ix, delta| {
match animation_ix {
0 => {
let chars_to_show = (delta * text.len() as f32).ceil() as usize;
let text = SharedString::from(text[0..chars_to_show].to_string());
label.set_text(text);
}
label
},
)
.with_animation(
"pulsating-label",
Animation::new(Duration::from_secs(2))
.repeat()
.with_easing(pulsating_between(0.6, 1.)),
|label, delta| label.map_element(|label| label.alpha(delta)),
)
1 => match delta {
d if d < 0.25 => label.set_text(text.clone()),
d if d < 0.5 => label.set_text(format!("{}.", text)),
d if d < 0.75 => label.set_text(format!("{}..", text)),
_ => label.set_text(format!("{}...", text)),
},
_ => {}
}
label
},
)
}
}
@@ -8,6 +8,7 @@ pub enum SpinnerVariant {
#[default]
Dots,
DotsVariant,
Sand,
}
/// A spinner indication, based on the label component, that loops through
@@ -41,6 +42,11 @@ impl SpinnerVariant {
match self {
SpinnerVariant::Dots => vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
SpinnerVariant::DotsVariant => vec!["⣼", "⣹", "⢻", "⠿", "⡟", "⣏", "⣧", "⣶"],
SpinnerVariant::Sand => vec![
"⠁", "⠂", "⠄", "⡀", "⡈", "⡐", "⡠", "⣀", "⣁", "⣂", "⣄", "⣌", "⣔", "⣤", "⣥", "⣦",
"⣮", "⣶", "⣷", "⣿", "⡿", "⠿", "⢟", "⠟", "⡛", "⠛", "⠫", "⢋", "⠋", "⠍", "⡉", "⠉",
"⠑", "⠡", "⢁",
],
}
}
@@ -48,6 +54,7 @@ impl SpinnerVariant {
match self {
SpinnerVariant::Dots => Duration::from_millis(1000),
SpinnerVariant::DotsVariant => Duration::from_millis(1000),
SpinnerVariant::Sand => Duration::from_millis(2000),
}
}
@@ -55,6 +62,7 @@ impl SpinnerVariant {
match self {
SpinnerVariant::Dots => "spinner_label_dots",
SpinnerVariant::DotsVariant => "spinner_label_dots_variant",
SpinnerVariant::Sand => "spinner_label_dots_variant_2",
}
}
}
@@ -83,6 +91,10 @@ impl SpinnerLabel {
pub fn dots_variant() -> Self {
Self::with_variant(SpinnerVariant::DotsVariant)
}
pub fn sand() -> Self {
Self::with_variant(SpinnerVariant::Sand)
}
}
impl LabelCommon for SpinnerLabel {
@@ -185,6 +197,7 @@ impl Component for SpinnerLabel {
"Dots Variant",
SpinnerLabel::dots_variant().into_any_element(),
),
single_example("Sand Variant", SpinnerLabel::sand().into_any_element()),
];
Some(example_group(examples).vertical().into_any_element())