Cargo.lock 🔗
@@ -16064,6 +16064,7 @@ dependencies = [
"serde_json",
"settings",
"smol",
+ "telemetry",
"theme",
"theme_settings",
"ui",
Katie Geer and Bennet Bo Fenner created
Track new telemetry:
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [-] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Cargo.lock | 1
crates/agent_ui/src/agent_panel.rs | 59 +++++++++++--
crates/agent_ui/src/conversation_view.rs | 36 ++++++++
crates/agent_ui/src/conversation_view/thread_view.rs | 11 ++
crates/agent_ui/src/threads_archive_view.rs | 9 ++
crates/agent_ui/src/ui/mention_crease.rs | 1
crates/sidebar/Cargo.toml | 1
crates/sidebar/src/sidebar.rs | 15 +++
crates/workspace/src/multi_workspace.rs | 29 ++++++
crates/workspace/src/workspace.rs | 2
10 files changed, 149 insertions(+), 15 deletions(-)
@@ -16064,6 +16064,7 @@ dependencies = [
"serde_json",
"settings",
"smol",
+ "telemetry",
"theme",
"theme_settings",
"ui",
@@ -223,7 +223,7 @@ pub fn init(cx: &mut App) {
if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
workspace.focus_panel::<AgentPanel>(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<Self>) -> ThreadId {
+ pub fn create_thread(
+ &mut self,
+ source: &'static str,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) -> 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<SharedString>,
initial_content: Option<AgentInitialContent>,
focus: bool,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -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<PathList>,
title: Option<SharedString>,
focus: bool,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -2563,6 +2583,7 @@ impl AgentPanel {
title,
None,
focus,
+ source,
window,
cx,
);
@@ -2575,6 +2596,7 @@ impl AgentPanel {
work_dirs: Option<PathList>,
title: Option<SharedString>,
initial_content: Option<AgentInitialContent>,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) -> AgentThread {
@@ -2585,6 +2607,7 @@ impl AgentPanel {
work_dirs,
title,
initial_content,
+ source,
window,
cx,
)
@@ -2598,6 +2621,7 @@ impl AgentPanel {
work_dirs: Option<PathList>,
title: Option<SharedString>,
initial_content: Option<AgentInitialContent>,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) -> 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<Self>) {
+ 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,
);
@@ -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<Project>,
thread_store: Option<Entity<ThreadStore>>,
prompt_store: Option<Entity<PromptStore>>,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) -> 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<SharedString>,
project: Entity<Project>,
initial_content: Option<AgentInitialContent>,
+ source: &'static str,
window: &mut Window,
cx: &mut Context<Self>,
) -> 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,
)
@@ -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(|_| ())
});
@@ -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);
})
})
@@ -284,6 +284,7 @@ fn open_thread(
None,
Some(name.into()),
true,
+ "agent_panel",
window,
cx,
)
@@ -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
@@ -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<Self>) {
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),
}
}
@@ -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<Self>) {
+ 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>) {
+ self.apply_open_sidebar(cx);
+ }
+
+ fn apply_open_sidebar(&mut self, cx: &mut Context<Self>) {
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<Self>) {
+ 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();
}
@@ -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();
}