diff --git a/Cargo.lock b/Cargo.lock index 02436cf80ead15ec38a7a88fba14f97a1b319618..ec232567bfd282c2f4e36e0e2d032c652bb54c08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16064,6 +16064,7 @@ dependencies = [ "serde_json", "settings", "smol", + "telemetry", "theme", "theme_settings", "ui", diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 184f5c1ee9adbb654fa31235c369e3f92755a0a6..413bad667825f05ad6b399677877fb2ec99cb7c9 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -223,7 +223,7 @@ pub fn init(cx: &mut App) { if let Some(panel) = workspace.panel::(cx) { workspace.focus_panel::(window, cx); panel.update(cx, |panel, cx| { - let id = panel.create_thread(window, cx); + let id = panel.create_thread("agent_panel", window, cx); panel.activate_retained_thread(id, true, window, cx); }); } @@ -364,6 +364,7 @@ pub fn init(cx: &mut App) { auto_submit: true, }), true, + "agent_panel", window, cx, ); @@ -390,6 +391,7 @@ pub fn init(cx: &mut App) { auto_submit: true, }), true, + "agent_panel", window, cx, ); @@ -418,6 +420,7 @@ pub fn init(cx: &mut App) { auto_submit: true, }), true, + "agent_panel", window, cx, ); @@ -925,6 +928,7 @@ impl AgentPanel { thread_info.work_dirs.as_ref().map(|dirs| PathList::deserialize(dirs)), thread_info.title.as_ref().map(|t| t.clone().into()), false, + "agent_panel", window, cx, ); @@ -955,6 +959,7 @@ impl AgentPanel { None, None, initial_content, + "agent_panel", window, cx, ); @@ -1256,6 +1261,7 @@ impl AgentPanel { work_dirs, title, true, + "agent_panel", window, cx, ); @@ -1330,7 +1336,8 @@ impl AgentPanel { } else { self.selected_agent.clone() }; - let thread = self.create_agent_thread(agent, None, None, None, None, window, cx); + let thread = + self.create_agent_thread(agent, None, None, None, None, "agent_panel", window, cx); self.draft_thread = Some(thread.conversation_view.clone()); self.observe_draft_editor(&thread.conversation_view, cx); thread.conversation_view @@ -1360,13 +1367,18 @@ impl AgentPanel { } } - pub fn create_thread(&mut self, window: &mut Window, cx: &mut Context) -> ThreadId { + pub fn create_thread( + &mut self, + source: &'static str, + window: &mut Window, + cx: &mut Context, + ) -> ThreadId { let agent = if self.project.read(cx).is_via_collab() { Agent::NativeAgent } else { self.selected_agent.clone() }; - let thread = self.create_agent_thread(agent, None, None, None, None, window, cx); + let thread = self.create_agent_thread(agent, None, None, None, None, source, window, cx); let thread_id = thread.conversation_view.read(cx).thread_id; self.retained_threads .insert(thread_id, thread.conversation_view); @@ -1532,6 +1544,7 @@ impl AgentPanel { title: thread.title, }), true, + "agent_panel", window, cx, ); @@ -1549,6 +1562,7 @@ impl AgentPanel { title: Option, initial_content: Option, focus: bool, + source: &'static str, window: &mut Window, cx: &mut Context, ) { @@ -1565,6 +1579,7 @@ impl AgentPanel { work_dirs, title, initial_content, + source, window, cx, ); @@ -1651,6 +1666,7 @@ impl AgentPanel { thread.work_dirs.clone(), thread.title.clone(), true, + "agent_panel", window, cx, ); @@ -2383,6 +2399,7 @@ impl AgentPanel { entry.work_dirs.clone(), entry.title.clone(), true, + "agent_panel", window, cx, ); @@ -2467,6 +2484,7 @@ impl AgentPanel { None, external_source_prompt.map(AgentInitialContent::from), true, + "agent_panel", window, cx, ); @@ -2491,6 +2509,7 @@ impl AgentPanel { None, initial_content, focus, + "agent_panel", window, cx, ); @@ -2507,6 +2526,7 @@ impl AgentPanel { work_dirs: Option, title: Option, focus: bool, + source: &'static str, window: &mut Window, cx: &mut Context, ) { @@ -2563,6 +2583,7 @@ impl AgentPanel { title, None, focus, + source, window, cx, ); @@ -2575,6 +2596,7 @@ impl AgentPanel { work_dirs: Option, title: Option, initial_content: Option, + source: &'static str, window: &mut Window, cx: &mut Context, ) -> AgentThread { @@ -2585,6 +2607,7 @@ impl AgentPanel { work_dirs, title, initial_content, + source, window, cx, ) @@ -2598,6 +2621,7 @@ impl AgentPanel { work_dirs: Option, title: Option, initial_content: Option, + source: &'static str, window: &mut Window, cx: &mut Context, ) -> AgentThread { @@ -2650,6 +2674,7 @@ impl AgentPanel { project, thread_store, self.prompt_store.clone(), + source, window, cx, ) @@ -3644,6 +3669,7 @@ impl AgentPanel { None, Some(initial_content), true, + "agent_panel", window, cx, ); @@ -3720,6 +3746,11 @@ impl Panel for AgentPanel { } fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context) { + let side = match position { + DockPosition::Left => "left", + DockPosition::Right | DockPosition::Bottom => "right", + }; + telemetry::event!("Agent Panel Side Changed", side = side); settings::update_settings_file(self.fs.clone(), cx, move |settings, _| { settings .agent @@ -4202,8 +4233,6 @@ impl AgentPanel { let agent_server_store = agent_server_store; Rc::new(move |window, cx| { - telemetry::event!("New Thread Clicked"); - let active_thread = active_thread.clone(); Some(ContextMenu::build(window, cx, |menu, _window, cx| { menu.context(focus_handle.clone()) @@ -4246,7 +4275,11 @@ impl AgentPanel { { panel.update(cx, |panel, cx| { panel.selected_agent = Agent::NativeAgent; - let id = panel.create_thread(window, cx); + let id = panel.create_thread( + "agent_panel", + window, + cx, + ); panel.activate_retained_thread( id, true, window, cx, ); @@ -4333,8 +4366,11 @@ impl AgentPanel { panel.selected_agent = Agent::Custom { id: agent_id.clone(), }; - let id = - panel.create_thread(window, cx); + let id = panel.create_thread( + "agent_panel", + window, + cx, + ); panel.activate_retained_thread( id, true, window, cx, ); @@ -5095,6 +5131,7 @@ impl AgentPanel { None, None, None, + "agent_panel", window, cx, ); @@ -5153,6 +5190,7 @@ impl AgentPanel { None, None, None, + "agent_panel", window, cx, ); @@ -6172,6 +6210,7 @@ mod tests { None, None, true, + "agent_panel", window, cx, ); @@ -6220,6 +6259,7 @@ mod tests { None, None, true, + "agent_panel", window, cx, ); @@ -7908,6 +7948,7 @@ mod tests { None, None, true, + "agent_panel", window, cx, ); diff --git a/crates/agent_ui/src/conversation_view.rs b/crates/agent_ui/src/conversation_view.rs index 63d0d08c2d8cb4a730cdb0100f98e6667872a9c6..4607f49190f1517180a08f4816df88ebd6d05662 100644 --- a/crates/agent_ui/src/conversation_view.rs +++ b/crates/agent_ui/src/conversation_view.rs @@ -46,7 +46,10 @@ use prompt_store::{PromptId, PromptStore}; use crate::DEFAULT_THREAD_TITLE; use crate::message_editor::SessionCapabilities; use rope::Point; -use settings::{NotifyWhenAgentWaiting, Settings as _, SettingsStore, ThinkingBlockDisplay}; +use settings::{ + NewThreadLocation, NotifyWhenAgentWaiting, Settings as _, SettingsStore, SidebarSide, + ThinkingBlockDisplay, +}; use std::path::Path; use std::sync::Arc; use std::time::Instant; @@ -659,6 +662,7 @@ impl ConversationView { project: Entity, thread_store: Option>, prompt_store: Option>, + source: &'static str, window: &mut Window, cx: &mut Context, ) -> Self { @@ -709,6 +713,7 @@ impl ConversationView { title, project, initial_content, + source, window, cx, ), @@ -753,6 +758,7 @@ impl ConversationView { title, self.project.clone(), None, + "agent_panel", window, cx, ); @@ -777,6 +783,7 @@ impl ConversationView { title: Option, project: Entity, initial_content: Option, + source: &'static str, window: &mut Window, cx: &mut Context, ) -> ServerState { @@ -809,6 +816,15 @@ impl ConversationView { let connect_result = connection_entry.read(cx).wait_for_connection(); + let side = match AgentSettings::get_global(cx).sidebar_side() { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + let thread_location = match AgentSettings::get_global(cx).new_thread_location { + NewThreadLocation::LocalProject => "current_worktree", + NewThreadLocation::NewWorktree => "new_worktree", + }; + let load_task = cx.spawn_in(window, async move |this, cx| { let (connection, history) = match connect_result.await { Ok(AgentConnectedState { @@ -825,7 +841,13 @@ impl ConversationView { } }; - telemetry::event!("Agent Thread Started", agent = connection.telemetry_id()); + telemetry::event!( + "Agent Thread Started", + agent = connection.telemetry_id(), + source = source, + side = side, + thread_location = thread_location + ); let mut resumed_without_history = false; let result = if let Some(session_id) = resume_session_id.clone() { @@ -2642,6 +2664,7 @@ impl ConversationView { root_work_dirs.clone(), root_title.clone(), true, + "agent_panel", window, cx, ); @@ -3151,6 +3174,7 @@ pub(crate) mod tests { project, Some(thread_store), None, + "agent_panel", window, cx, ) @@ -3287,6 +3311,7 @@ pub(crate) mod tests { project, Some(thread_store), None, + "agent_panel", window, cx, ) @@ -3368,6 +3393,7 @@ pub(crate) mod tests { project, Some(thread_store), None, + "agent_panel", window, cx, ) @@ -3690,6 +3716,7 @@ pub(crate) mod tests { project.clone(), Some(thread_store), None, + "agent_panel", window, cx, ) @@ -3787,6 +3814,7 @@ pub(crate) mod tests { project.clone(), Some(thread_store), None, + "agent_panel", window, cx, ) @@ -3889,6 +3917,7 @@ pub(crate) mod tests { project1.clone(), Some(thread_store), None, + "agent_panel", window, cx, ) @@ -4136,6 +4165,7 @@ pub(crate) mod tests { project, Some(thread_store), None, + "agent_panel", window, cx, ) @@ -4906,6 +4936,7 @@ pub(crate) mod tests { project.clone(), Some(thread_store.clone()), None, + "agent_panel", window, cx, ) @@ -7238,6 +7269,7 @@ pub(crate) mod tests { project, Some(thread_store), None, + "agent_panel", window, cx, ) diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index 1be0c0908da170e794ee495c4c4ef6ff0924b5ac..95d3f3599b41a5028a6bed6fa51c179eb51e767f 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -14,7 +14,7 @@ use crate::message_editor::SharedSessionCapabilities; use gpui::{Corner, List}; use heapless::Vec as ArrayVec; use language_model::{LanguageModelEffortLevel, Speed}; -use settings::update_settings_file; +use settings::{SidebarSide, update_settings_file}; use ui::{ButtonLike, SpinnerLabel, SpinnerVariant, SplitButton, SplitButtonStyle, Tab}; use workspace::SERIALIZATION_THROTTLE_TIME; @@ -1031,6 +1031,11 @@ impl ThreadView { }) .detach(); + let side = match AgentSettings::get_global(cx).sidebar_side() { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + let task = cx.spawn_in(window, async move |this, cx| { let Some((contents, tracked_buffers)) = contents_task.await? else { return Ok(()); @@ -1099,7 +1104,8 @@ impl ThreadView { session = session_id, parent_session_id = parent_session_id.as_ref().map(|id| id.to_string()), model = model_id, - mode = mode_id + mode = mode_id, + side = side ); thread.send(contents, cx) @@ -1128,6 +1134,7 @@ impl ThreadView { mode = mode_id, status, turn_time_ms, + side = side ); res.map(|_| ()) }); diff --git a/crates/agent_ui/src/threads_archive_view.rs b/crates/agent_ui/src/threads_archive_view.rs index 69bf0761183ef3624130419564cf15c05c4a4e00..e9101b1553837d7ba82dc0d1550fe11c51591a37 100644 --- a/crates/agent_ui/src/threads_archive_view.rs +++ b/crates/agent_ui/src/threads_archive_view.rs @@ -668,6 +668,15 @@ impl ThreadsArchiveView { .on_click({ let thread = thread.clone(); cx.listener(move |this, _, window, cx| { + let side = match AgentSettings::get_global(cx).sidebar_side() { + settings::SidebarSide::Left => "left", + settings::SidebarSide::Right => "right", + }; + telemetry::event!( + "Archived Thread Opened", + agent = thread.agent_id.as_ref(), + side = side + ); this.unarchive_thread(thread.clone(), window, cx); }) }) diff --git a/crates/agent_ui/src/ui/mention_crease.rs b/crates/agent_ui/src/ui/mention_crease.rs index bd48a558f5d9b1f042f974dc6e174f8ba8078adf..9fa245516f950b31201f41a45389e41837b07b56 100644 --- a/crates/agent_ui/src/ui/mention_crease.rs +++ b/crates/agent_ui/src/ui/mention_crease.rs @@ -284,6 +284,7 @@ fn open_thread( None, Some(name.into()), true, + "agent_panel", window, cx, ) diff --git a/crates/sidebar/Cargo.toml b/crates/sidebar/Cargo.toml index dcc960141e32676bb371f22b25fd58ed58e6f89f..4ac1257d94a417c56bbfd90366a01c7f64bb003a 100644 --- a/crates/sidebar/Cargo.toml +++ b/crates/sidebar/Cargo.toml @@ -38,6 +38,7 @@ serde.workspace = true serde_json.workspace = true settings.workspace = true smol.workspace = true +telemetry.workspace = true theme.workspace = true theme_settings.workspace = true ui.workspace = true diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index c7b1c6fc8e13d1cde7b9868728848df587d93553..1c3b8ba018fd968556d4f37d9f39598214f8cc04 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -2216,6 +2216,7 @@ impl Sidebar { Some(metadata.folder_paths().clone()), metadata.title.clone(), focus, + "sidebar", window, cx, ); @@ -4201,6 +4202,11 @@ impl Sidebar { .full_width() .key_binding(KeyBinding::for_action(&workspace::Open::default(), cx)) .on_click(|_, window, cx| { + let side = match AgentSettings::get_global(cx).sidebar_side() { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + telemetry::event!("Sidebar Add Project Clicked", side = side); window.dispatch_action( Open { create_new_window: false, @@ -4518,7 +4524,14 @@ impl Sidebar { fn toggle_archive(&mut self, _: &ToggleArchive, window: &mut Window, cx: &mut Context) { match &self.view { - SidebarView::ThreadList => self.show_archive(window, cx), + SidebarView::ThreadList => { + let side = match self.side(cx) { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + telemetry::event!("Sidebar Archive Viewed", side = side); + self.show_archive(window, cx); + } SidebarView::Archive(_) => self.show_thread_list(window, cx), } } diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index 228597971e5815bdc6a97f13415053f9e78a0a80..d359a44e4474b1d1caebfd6d357588a61cbfd670 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -87,6 +87,11 @@ pub fn sidebar_side_context_menu( IconPosition::Start, None, move |_window, cx| { + let side = match position { + SidebarDockPosition::Left => "left", + SidebarDockPosition::Right => "right", + }; + telemetry::event!("Sidebar Side Changed", side = side); settings::update_settings_file(fs.clone(), cx, move |settings, _cx| { settings .agent @@ -458,6 +463,21 @@ impl MultiWorkspace { } pub fn open_sidebar(&mut self, cx: &mut Context) { + let side = match self.sidebar_side(cx) { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + telemetry::event!("Sidebar Toggled", action = "open", side = side); + self.apply_open_sidebar(cx); + } + + /// Restores the sidebar to open state from persisted session data without + /// firing a telemetry event, since this is not a user-initiated action. + pub(crate) fn restore_open_sidebar(&mut self, cx: &mut Context) { + self.apply_open_sidebar(cx); + } + + fn apply_open_sidebar(&mut self, cx: &mut Context) { self.sidebar_open = true; self.retain_active_workspace(cx); let sidebar_focus_handle = self.sidebar.as_ref().map(|s| s.focus_handle(cx)); @@ -471,6 +491,11 @@ impl MultiWorkspace { } pub fn close_sidebar(&mut self, window: &mut Window, cx: &mut Context) { + let side = match self.sidebar_side(cx) { + SidebarSide::Left => "left", + SidebarSide::Right => "right", + }; + telemetry::event!("Sidebar Toggled", action = "close", side = side); self.sidebar_open = false; for workspace in self.retained_workspaces.clone() { workspace.update(cx, |workspace, _cx| { @@ -1179,6 +1204,10 @@ impl MultiWorkspace { let key = workspace.read(cx).project_group_key(cx); self.retain_workspace(workspace, key, cx); + telemetry::event!( + "Workspace Added", + workspace_count = self.retained_workspaces.len() + ); cx.notify(); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f67a9b0e331e16afb026307cbeb49f0191cc5537..feaf717a1fc8e5d2224fa161f9caca972297065d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -8842,7 +8842,7 @@ pub async fn apply_restored_multiworkspace_state( if *sidebar_open { window_handle .update(cx, |multi_workspace, _, cx| { - multi_workspace.open_sidebar(cx); + multi_workspace.restore_open_sidebar(cx); }) .ok(); }