Detailed changes
@@ -22,6 +22,10 @@ impl NativeAgentServer {
}
impl AgentServer for NativeAgentServer {
+ fn telemetry_id(&self) -> &'static str {
+ "zed"
+ }
+
fn name(&self) -> SharedString {
"Zed Agent".into()
}
@@ -1685,6 +1685,7 @@ async fn test_truncate_second_message(cx: &mut TestAppContext) {
}
#[gpui::test]
+#[cfg_attr(target_os = "windows", ignore)] // TODO: Fix this test on Windows
async fn test_title_generation(cx: &mut TestAppContext) {
let ThreadTest { model, thread, .. } = setup(cx, TestModel::Fake).await;
let fake_model = model.as_fake();
@@ -36,6 +36,7 @@ pub trait AgentServer: Send {
fn name(&self) -> SharedString;
fn empty_state_headline(&self) -> SharedString;
fn empty_state_message(&self) -> SharedString;
+ fn telemetry_id(&self) -> &'static str;
fn connect(
&self,
@@ -43,6 +43,10 @@ use acp_thread::{AcpThread, AgentConnection, AuthRequired, LoadError, MentionUri
pub struct ClaudeCode;
impl AgentServer for ClaudeCode {
+ fn telemetry_id(&self) -> &'static str {
+ "claude-code"
+ }
+
fn name(&self) -> SharedString {
"Claude Code".into()
}
@@ -22,6 +22,10 @@ impl CustomAgentServer {
}
impl crate::AgentServer for CustomAgentServer {
+ fn telemetry_id(&self) -> &'static str {
+ "custom"
+ }
+
fn name(&self) -> SharedString {
self.name.clone()
}
@@ -17,6 +17,10 @@ pub struct Gemini;
const ACP_ARG: &str = "--experimental-acp";
impl AgentServer for Gemini {
+ fn telemetry_id(&self) -> &'static str {
+ "gemini-cli"
+ }
+
fn name(&self) -> SharedString {
"Gemini CLI".into()
}
@@ -892,6 +892,8 @@ impl AcpThreadView {
window: &mut Window,
cx: &mut Context<Self>,
) {
+ let agent_telemetry_id = self.agent.telemetry_id();
+
self.thread_error.take();
self.editing_message.take();
self.thread_feedback.clear();
@@ -936,6 +938,9 @@ impl AcpThreadView {
}
});
drop(guard);
+
+ telemetry::event!("Agent Message Sent", agent = agent_telemetry_id);
+
thread.send(contents, cx)
})?;
send.await
@@ -1246,30 +1251,44 @@ impl AcpThreadView {
pending_auth_method.replace(method.clone());
let authenticate = connection.authenticate(method, cx);
cx.notify();
- self.auth_task = Some(cx.spawn_in(window, {
- let project = self.project.clone();
- let agent = self.agent.clone();
- async move |this, cx| {
- let result = authenticate.await;
+ self.auth_task =
+ Some(cx.spawn_in(window, {
+ let project = self.project.clone();
+ let agent = self.agent.clone();
+ async move |this, cx| {
+ let result = authenticate.await;
- this.update_in(cx, |this, window, cx| {
- if let Err(err) = result {
- this.handle_thread_error(err, cx);
- } else {
- this.thread_state = Self::initial_state(
- agent,
- None,
- this.workspace.clone(),
- project.clone(),
- window,
- cx,
- )
+ match &result {
+ Ok(_) => telemetry::event!(
+ "Authenticate Agent Succeeded",
+ agent = agent.telemetry_id()
+ ),
+ Err(_) => {
+ telemetry::event!(
+ "Authenticate Agent Failed",
+ agent = agent.telemetry_id(),
+ )
+ }
}
- this.auth_task.take()
- })
- .ok();
- }
- }));
+
+ this.update_in(cx, |this, window, cx| {
+ if let Err(err) = result {
+ this.handle_thread_error(err, cx);
+ } else {
+ this.thread_state = Self::initial_state(
+ agent,
+ None,
+ this.workspace.clone(),
+ project.clone(),
+ window,
+ cx,
+ )
+ }
+ this.auth_task.take()
+ })
+ .ok();
+ }
+ }));
}
fn authorize_tool_call(
@@ -2776,6 +2795,12 @@ impl AcpThreadView {
.on_click({
let method_id = method.id.clone();
cx.listener(move |this, _, window, cx| {
+ telemetry::event!(
+ "Authenticate Agent Started",
+ agent = this.agent.telemetry_id(),
+ method = method_id
+ );
+
this.authenticate(method_id.clone(), window, cx)
})
})
@@ -2804,6 +2829,8 @@ impl AcpThreadView {
.icon_color(Color::Muted)
.icon_position(IconPosition::Start)
.on_click(cx.listener(move |this, _, window, cx| {
+ telemetry::event!("Agent Install CLI", agent = this.agent.telemetry_id());
+
let task = this
.workspace
.update(cx, |workspace, cx| {
@@ -2861,6 +2888,8 @@ impl AcpThreadView {
.icon_color(Color::Muted)
.icon_position(IconPosition::Start)
.on_click(cx.listener(move |this, _, window, cx| {
+ telemetry::event!("Agent Upgrade CLI", agent = this.agent.telemetry_id());
+
let task = this
.workspace
.update(cx, |workspace, cx| {
@@ -3708,6 +3737,8 @@ impl AcpThreadView {
}
})
.ok();
+
+ telemetry::event!("Follow Agent Selected", following = !following);
}
fn render_follow_toggle(&self, cx: &mut Context<Self>) -> impl IntoElement {
@@ -5323,6 +5354,10 @@ pub(crate) mod tests {
where
C: 'static + AgentConnection + Send + Clone,
{
+ fn telemetry_id(&self) -> &'static str {
+ "test"
+ }
+
fn logo(&self) -> ui::IconName {
ui::IconName::Ai
}
@@ -1026,6 +1026,8 @@ impl AgentPanel {
}
fn new_prompt_editor(&mut self, window: &mut Window, cx: &mut Context<Self>) {
+ telemetry::event!("Agent Thread Started", agent = "zed-text");
+
let context = self
.context_store
.update(cx, |context_store, cx| context_store.create(cx));
@@ -1118,6 +1120,8 @@ impl AgentPanel {
}
};
+ telemetry::event!("Agent Thread Started", agent = ext_agent.name());
+
let server = ext_agent.server(fs, history);
this.update_in(cx, |this, window, cx| {
@@ -2327,6 +2331,8 @@ impl AgentPanel {
.menu({
let menu = self.assistant_navigation_menu.clone();
move |window, cx| {
+ telemetry::event!("View Thread History Clicked");
+
if let Some(menu) = menu.as_ref() {
menu.update(cx, |_, cx| {
cx.defer_in(window, |menu, window, cx| {
@@ -2505,6 +2511,8 @@ impl AgentPanel {
let workspace = self.workspace.clone();
move |window, cx| {
+ telemetry::event!("New Thread Clicked");
+
let active_thread = active_thread.clone();
Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
menu = menu
@@ -175,6 +175,15 @@ enum ExternalAgent {
}
impl ExternalAgent {
+ fn name(&self) -> &'static str {
+ match self {
+ Self::NativeAgent => "zed",
+ Self::Gemini => "gemini-cli",
+ Self::ClaudeCode => "claude-code",
+ Self::Custom { .. } => "custom",
+ }
+ }
+
pub fn server(
&self,
fs: Arc<dyn fs::Fs>,
@@ -361,6 +361,7 @@ impl TextThreadEditor {
if self.sending_disabled(cx) {
return;
}
+ telemetry::event!("Agent Message Sent", agent = "zed-text");
self.send_to_model(window, cx);
}