Complete remaining telemetry events for sidebar and agent panel

Katie Geer created

Sidebar Side Changed (item 1):
  Fires in sidebar_side_context_menu when user picks a side from the
  right-click menu on the sidebar toggle button.

side property on View Thread History Clicked (item 2):
  Adds agent_panel_side_str helper (alongside the existing helpers) and
  threads it through the navigation menu builder closure.

side property on core agent funnel events (item 3):
  - Agent Thread Started: side captured before the spawn_in in
    conversation_view.rs and moved into the async closure.
  - Agent Message Sent / Agent Turn Completed: side captured once before
    the send_content spawn_in in thread_view.rs and shared by both events
    in the same async block.

Sidebar Archive Viewed + Archived Thread Opened (item 4):
  - Sidebar Archive Viewed fires in toggle_archive when transitioning
    from thread list to archive view (not on deserialization restore).
  - Archived Thread Opened fires on the row on_click in
    ThreadsArchiveView before unarchive_thread is called.

Start Thread In Changed (item 5):
  Fires in set_start_thread_in after all validation guards pass and
  self.start_thread_in is assigned, covering all call paths including
  direct dispatch, the picker confirm, and cycle_start_thread_in.

Change summary

crates/agent_ui/src/agent_panel.rs                   | 17 ++++++++++++++
crates/agent_ui/src/conversation_view.rs             | 10 +++++++
crates/agent_ui/src/conversation_view/thread_view.rs | 10 ++++++-
crates/agent_ui/src/threads_archive_view.rs          |  5 ++++
crates/sidebar/src/sidebar.rs                        |  9 ++++++
crates/workspace/src/multi_workspace.rs              |  5 ++++
6 files changed, 52 insertions(+), 4 deletions(-)

Detailed changes

crates/agent_ui/src/agent_panel.rs 🔗

@@ -2256,6 +2256,16 @@ impl AgentPanel {
             }
         };
         self.start_thread_in = new_target;
+        let target = match &self.start_thread_in {
+            StartThreadIn::LocalProject => "current_worktree",
+            StartThreadIn::NewWorktree { .. } => "new_worktree",
+            StartThreadIn::LinkedWorktree { .. } => "linked_worktree",
+        };
+        telemetry::event!(
+            "Start Thread In Changed",
+            target = target,
+            side = agent_panel_side_str(cx)
+        );
         if let Some(thread) = self.active_thread_view(cx) {
             thread.update(cx, |thread, cx| thread.focus_handle(cx).focus(window, cx));
         }
@@ -3334,6 +3344,13 @@ fn agent_panel_dock_position(cx: &App) -> DockPosition {
     AgentSettings::get_global(cx).dock.into()
 }
 
+fn agent_panel_side_str(cx: &App) -> &'static str {
+    match agent_panel_dock_position(cx) {
+        DockPosition::Left => "left",
+        DockPosition::Right | DockPosition::Bottom => "right",
+    }
+}
+
 fn thread_location_str(cx: &App) -> &'static str {
     use settings::{NewThreadLocation, Settings};
     match AgentSettings::get_global(cx).new_thread_location {

crates/agent_ui/src/conversation_view.rs 🔗

@@ -669,6 +669,10 @@ impl ConversationView {
         let connect_result = connection_entry.read(cx).wait_for_connection();
 
         let load_session_id = resume_session_id.clone();
+        let side = match AgentSettings::get_global(cx).dock {
+            settings::DockPosition::Left => "left",
+            settings::DockPosition::Right | settings::DockPosition::Bottom => "right",
+        };
         let load_task = cx.spawn_in(window, async move |this, cx| {
             let (connection, history) = match connect_result.await {
                 Ok(AgentConnectedState {
@@ -685,7 +689,11 @@ impl ConversationView {
                 }
             };
 
-            telemetry::event!("Agent Thread Started", agent = connection.telemetry_id());
+            telemetry::event!(
+                "Agent Thread Started",
+                agent = connection.telemetry_id(),
+                side = side
+            );
 
             let mut resumed_without_history = false;
             let result = if let Some(session_id) = load_session_id.clone() {

crates/agent_ui/src/conversation_view/thread_view.rs 🔗

@@ -13,7 +13,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::{DockPosition, update_settings_file};
 use ui::{ButtonLike, SpinnerLabel, SpinnerVariant, SplitButton, SplitButtonStyle, Tab};
 use workspace::SERIALIZATION_THROTTLE_TIME;
 
@@ -1066,6 +1066,10 @@ impl ThreadView {
         })
         .detach();
 
+        let side = match AgentSettings::get_global(cx).dock {
+            DockPosition::Left => "left",
+            DockPosition::Right | DockPosition::Bottom => "right",
+        };
         let task = cx.spawn_in(window, async move |this, cx| {
             let Some((contents, tracked_buffers)) = contents_task.await? else {
                 return Ok(());
@@ -1134,7 +1138,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)
@@ -1163,6 +1168,7 @@ impl ThreadView {
                 mode = mode_id,
                 status,
                 turn_time_ms,
+                side = side
             );
             res.map(|_| ())
         });

crates/agent_ui/src/threads_archive_view.rs 🔗

@@ -557,6 +557,11 @@ 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", side = side);
                             this.unarchive_thread(thread.clone(), window, cx);
                         })
                     })

crates/sidebar/src/sidebar.rs 🔗

@@ -3841,7 +3841,14 @@ impl Sidebar {
 
     fn toggle_archive(&mut self, _: &ToggleArchive, window: &mut Window, cx: &mut Context<Self>) {
         match &self.view {
-            SidebarView::ThreadList => self.show_archive(window, cx),
+            SidebarView::ThreadList => {
+                let side = match AgentSettings::get_global(cx).sidebar_side() {
+                    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),
         }
     }

crates/workspace/src/multi_workspace.rs 🔗

@@ -80,6 +80,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