acp: Add telemetry (#36894)

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Bennet Bo Fenner 2025-08-25 20:51:23 +02:00 committed by GitHub
parent c786c0150f
commit 59af2a7d1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 93 additions and 22 deletions

View file

@ -22,6 +22,10 @@ impl NativeAgentServer {
}
impl AgentServer for NativeAgentServer {
fn telemetry_id(&self) -> &'static str {
"zed"
}
fn name(&self) -> SharedString {
"Zed Agent".into()
}

View file

@ -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();

View file

@ -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,

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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,12 +1251,26 @@ impl AcpThreadView {
pending_auth_method.replace(method.clone());
let authenticate = connection.authenticate(method, cx);
cx.notify();
self.auth_task = Some(cx.spawn_in(window, {
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;
match &result {
Ok(_) => telemetry::event!(
"Authenticate Agent Succeeded",
agent = agent.telemetry_id()
),
Err(_) => {
telemetry::event!(
"Authenticate Agent Failed",
agent = agent.telemetry_id(),
)
}
}
this.update_in(cx, |this, window, cx| {
if let Err(err) = result {
this.handle_thread_error(err, cx);
@ -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
}

View file

@ -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

View file

@ -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>,

View file

@ -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);
}