zeta: Show timestamps and latency in rating modal (#21863)

Thorsten Ball , Antonio , Bennet , and Cole created

Release Notes:

- N/A

---------

Co-authored-by: Antonio <antonio@zed.dev>
Co-authored-by: Bennet <bennet@zed.dev>
Co-authored-by: Cole <cole@zed.dev>

Change summary

crates/zeta/src/rate_completion_modal.rs | 39 +++++++++++++++++++------
crates/zeta/src/zeta.rs                  | 17 ++++++++++-
2 files changed, 44 insertions(+), 12 deletions(-)

Detailed changes

crates/zeta/src/rate_completion_modal.rs 🔗

@@ -5,8 +5,8 @@ use gpui::{
     HighlightStyle, Model, StyledText, TextStyle, View, ViewContext,
 };
 use language::{language_settings, OffsetRangeExt};
-
 use settings::Settings;
+use std::time::Duration;
 use theme::ThemeSettings;
 use ui::{prelude::*, KeyBinding, List, ListItem, ListItemSpacing, TintColor, Tooltip};
 use workspace::{ModalView, Workspace};
@@ -530,6 +530,7 @@ impl Render for RateCompletionModal {
                                         });
                                     let rated =
                                         self.zeta.read(cx).is_completion_rated(completion.id);
+
                                     ListItem::new(completion.id)
                                         .inset(true)
                                         .spacing(ListItemSpacing::Sparse)
@@ -542,16 +543,17 @@ impl Render for RateCompletionModal {
                                         } else {
                                             Icon::new(IconName::FileDiff).color(Color::Accent).size(IconSize::Small)
                                         })
-                                        .child(Label::new(
-                                            completion.path.to_string_lossy().to_string(),
-                                        ).size(LabelSize::Small))
                                         .child(
-                                            div()
-                                                .overflow_hidden()
-                                                .text_ellipsis()
-                                                .child(Label::new(format!("({})", completion.id))
-                                                    .color(Color::Muted)
-                                                    .size(LabelSize::XSmall)),
+                                            v_flex()
+                                                .child(Label::new(completion.path.to_string_lossy().to_string()).size(LabelSize::Small))
+                                                .child(div()
+                                                    .overflow_hidden()
+                                                    .text_ellipsis()
+                                                    .child(Label::new(format!("{} ago, {:.2?}", format_time_ago(completion.response_received_at.elapsed()), completion.latency()))
+                                                        .color(Color::Muted)
+                                                        .size(LabelSize::XSmall)
+                                                    )
+                                                )
                                         )
                                         .on_click(cx.listener(move |this, _, cx| {
                                             this.select_completion(Some(completion.clone()), true, cx);
@@ -574,3 +576,20 @@ impl FocusableView for RateCompletionModal {
 }
 
 impl ModalView for RateCompletionModal {}
+
+fn format_time_ago(elapsed: Duration) -> String {
+    let seconds = elapsed.as_secs();
+    if seconds < 120 {
+        "1 minute".to_string()
+    } else if seconds < 3600 {
+        format!("{} minutes", seconds / 60)
+    } else if seconds < 7200 {
+        "1 hour".to_string()
+    } else if seconds < 86400 {
+        format!("{} hours", seconds / 3600)
+    } else if seconds < 172800 {
+        "1 day".to_string()
+    } else {
+        format!("{} days", seconds / 86400)
+    }
+}

crates/zeta/src/zeta.rs 🔗

@@ -76,9 +76,16 @@ pub struct InlineCompletion {
     input_events: Arc<str>,
     input_excerpt: Arc<str>,
     output_excerpt: Arc<str>,
+    request_sent_at: Instant,
+    response_received_at: Instant,
 }
 
 impl InlineCompletion {
+    fn latency(&self) -> Duration {
+        self.response_received_at
+            .duration_since(self.request_sent_at)
+    }
+
     fn interpolate(&self, new_snapshot: BufferSnapshot) -> Option<Vec<(Range<Anchor>, String)>> {
         let mut edits = Vec::new();
 
@@ -282,7 +289,7 @@ impl Zeta {
         let llm_token = self.llm_token.clone();
 
         cx.spawn(|this, mut cx| async move {
-            let start = std::time::Instant::now();
+            let request_sent_at = Instant::now();
 
             let mut input_events = String::new();
             for event in events {
@@ -304,7 +311,6 @@ impl Zeta {
             let response = perform_predict_edits(client, llm_token, body).await?;
 
             let output_excerpt = response.output_excerpt;
-            log::debug!("prediction took: {:?}", start.elapsed());
             log::debug!("completion response: {}", output_excerpt);
 
             let inline_completion = Self::process_completion_response(
@@ -314,6 +320,7 @@ impl Zeta {
                 path,
                 input_events,
                 input_excerpt,
+                request_sent_at,
                 &cx,
             )
             .await?;
@@ -539,6 +546,7 @@ and then another
         }
     }
 
+    #[allow(clippy::too_many_arguments)]
     fn process_completion_response(
         output_excerpt: String,
         snapshot: &BufferSnapshot,
@@ -546,6 +554,7 @@ and then another
         path: Arc<Path>,
         input_events: String,
         input_excerpt: String,
+        request_sent_at: Instant,
         cx: &AsyncAppContext,
     ) -> Task<Result<InlineCompletion>> {
         let snapshot = snapshot.clone();
@@ -580,6 +589,8 @@ and then another
                 input_events: input_events.into(),
                 input_excerpt: input_excerpt.into(),
                 output_excerpt: output_excerpt.into(),
+                request_sent_at,
+                response_received_at: Instant::now(),
             })
         })
     }
@@ -1027,6 +1038,8 @@ mod tests {
             input_events: "".into(),
             input_excerpt: "".into(),
             output_excerpt: "".into(),
+            request_sent_at: Instant::now(),
+            response_received_at: Instant::now(),
         };
 
         assert_eq!(