From fc2b3b2e451e199ae367d9f8385dbf85c910826e Mon Sep 17 00:00:00 2001 From: Bennet Fenner Date: Tue, 14 Oct 2025 17:23:47 +0200 Subject: [PATCH] agent: Remove unused `HistoryStore` (#40187) Release Notes: - N/A --- Cargo.lock | 1 - crates/agent/Cargo.toml | 1 - crates/agent/src/agent.rs | 1 - crates/agent/src/history_store.rs | 253 ----------------------------- crates/agent_ui/src/agent_panel.rs | 53 ++---- 5 files changed, 11 insertions(+), 298 deletions(-) delete mode 100644 crates/agent/src/history_store.rs diff --git a/Cargo.lock b/Cargo.lock index 471a82d83f766b4a1b73e7c8442f05047430caea..117b2a16cdb9bf582101ff400f07bd207bbc4e73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,7 +161,6 @@ dependencies = [ "http_client", "icons", "indoc", - "itertools 0.14.0", "language", "language_model", "log", diff --git a/crates/agent/Cargo.toml b/crates/agent/Cargo.toml index 76f96647c7af5692ca9b4b146e27f9f7c19c7995..ebd043d0c3c61bed287507e303637035a5b8156f 100644 --- a/crates/agent/Cargo.toml +++ b/crates/agent/Cargo.toml @@ -39,7 +39,6 @@ heed.workspace = true http_client.workspace = true icons.workspace = true indoc.workspace = true -itertools.workspace = true language.workspace = true language_model.workspace = true log.workspace = true diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index 9cd2a93d9bfc9a8a1940fea150f651b60f1a1073..056c380e78de576fd7b0c065e3e5de631fdc37bb 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -2,7 +2,6 @@ pub mod agent_profile; pub mod context; pub mod context_server_tool; pub mod context_store; -pub mod history_store; pub mod thread; pub mod thread_store; pub mod tool_use; diff --git a/crates/agent/src/history_store.rs b/crates/agent/src/history_store.rs deleted file mode 100644 index 4b1795047b7444dc74f8a41097c0c66aa54ecfd9..0000000000000000000000000000000000000000 --- a/crates/agent/src/history_store.rs +++ /dev/null @@ -1,253 +0,0 @@ -use crate::{ThreadId, thread_store::SerializedThreadMetadata}; -use anyhow::{Context as _, Result}; -use assistant_context::SavedContextMetadata; -use chrono::{DateTime, Utc}; -use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::*}; -use itertools::Itertools; -use paths::contexts_dir; -use serde::{Deserialize, Serialize}; -use std::{collections::VecDeque, path::Path, sync::Arc, time::Duration}; -use util::ResultExt as _; - -const MAX_RECENTLY_OPENED_ENTRIES: usize = 6; -const NAVIGATION_HISTORY_PATH: &str = "agent-navigation-history.json"; -const SAVE_RECENTLY_OPENED_ENTRIES_DEBOUNCE: Duration = Duration::from_millis(50); - -#[derive(Clone, Debug)] -pub enum HistoryEntry { - Thread(SerializedThreadMetadata), - Context(SavedContextMetadata), -} - -impl HistoryEntry { - pub fn updated_at(&self) -> DateTime { - match self { - HistoryEntry::Thread(thread) => thread.updated_at, - HistoryEntry::Context(context) => context.mtime.to_utc(), - } - } - - pub fn id(&self) -> HistoryEntryId { - match self { - HistoryEntry::Thread(thread) => HistoryEntryId::Thread(thread.id.clone()), - HistoryEntry::Context(context) => HistoryEntryId::Context(context.path.clone()), - } - } - - pub fn title(&self) -> &SharedString { - match self { - HistoryEntry::Thread(thread) => &thread.summary, - HistoryEntry::Context(context) => &context.title, - } - } -} - -/// Generic identifier for a history entry. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum HistoryEntryId { - Thread(ThreadId), - Context(Arc), -} - -#[derive(Serialize, Deserialize)] -enum SerializedRecentOpen { - Thread(String), - ContextName(String), - /// Old format which stores the full path - Context(String), -} - -pub struct HistoryStore { - context_store: Entity, - recently_opened_entries: VecDeque, - _subscriptions: Vec, - _save_recently_opened_entries_task: Task<()>, -} - -impl HistoryStore { - pub fn new( - context_store: Entity, - initial_recent_entries: impl IntoIterator, - cx: &mut Context, - ) -> Self { - let subscriptions = vec![cx.observe(&context_store, |_, _, cx| cx.notify())]; - - cx.spawn(async move |this, cx| { - let entries = Self::load_recently_opened_entries(cx).await.log_err()?; - this.update(cx, |this, _| { - this.recently_opened_entries - .extend( - entries.into_iter().take( - MAX_RECENTLY_OPENED_ENTRIES - .saturating_sub(this.recently_opened_entries.len()), - ), - ); - }) - .ok() - }) - .detach(); - - Self { - context_store, - recently_opened_entries: initial_recent_entries.into_iter().collect(), - _subscriptions: subscriptions, - _save_recently_opened_entries_task: Task::ready(()), - } - } - - pub fn entries(&self, cx: &mut Context) -> Vec { - let mut history_entries = Vec::new(); - - #[cfg(debug_assertions)] - if std::env::var("ZED_SIMULATE_NO_THREAD_HISTORY").is_ok() { - return history_entries; - } - - history_entries.extend( - self.context_store - .read(cx) - .unordered_contexts() - .cloned() - .map(HistoryEntry::Context), - ); - - history_entries.sort_unstable_by_key(|entry| std::cmp::Reverse(entry.updated_at())); - history_entries - } - - pub fn recent_entries(&self, limit: usize, cx: &mut Context) -> Vec { - self.entries(cx).into_iter().take(limit).collect() - } - - pub fn recently_opened_entries(&self, cx: &App) -> Vec { - #[cfg(debug_assertions)] - if std::env::var("ZED_SIMULATE_NO_THREAD_HISTORY").is_ok() { - return Vec::new(); - } - - let context_entries = - self.context_store - .read(cx) - .unordered_contexts() - .flat_map(|context| { - self.recently_opened_entries - .iter() - .enumerate() - .flat_map(|(index, entry)| match entry { - HistoryEntryId::Context(path) if &context.path == path => { - Some((index, HistoryEntry::Context(context.clone()))) - } - _ => None, - }) - }); - - context_entries - // optimization to halt iteration early - .take(self.recently_opened_entries.len()) - .sorted_unstable_by_key(|(index, _)| *index) - .map(|(_, entry)| entry) - .collect() - } - - fn save_recently_opened_entries(&mut self, cx: &mut Context) { - let serialized_entries = self - .recently_opened_entries - .iter() - .filter_map(|entry| match entry { - HistoryEntryId::Context(path) => path.file_name().map(|file| { - SerializedRecentOpen::ContextName(file.to_string_lossy().into_owned()) - }), - HistoryEntryId::Thread(id) => Some(SerializedRecentOpen::Thread(id.to_string())), - }) - .collect::>(); - - self._save_recently_opened_entries_task = cx.spawn(async move |_, cx| { - cx.background_executor() - .timer(SAVE_RECENTLY_OPENED_ENTRIES_DEBOUNCE) - .await; - cx.background_spawn(async move { - let path = paths::data_dir().join(NAVIGATION_HISTORY_PATH); - let content = serde_json::to_string(&serialized_entries)?; - std::fs::write(path, content)?; - anyhow::Ok(()) - }) - .await - .log_err(); - }); - } - - fn load_recently_opened_entries(cx: &AsyncApp) -> Task>> { - cx.background_spawn(async move { - let path = paths::data_dir().join(NAVIGATION_HISTORY_PATH); - let contents = match smol::fs::read_to_string(path).await { - Ok(it) => it, - Err(e) if e.kind() == std::io::ErrorKind::NotFound => { - return Ok(Vec::new()); - } - Err(e) => { - return Err(e) - .context("deserializing persisted agent panel navigation history"); - } - }; - let entries = serde_json::from_str::>(&contents) - .context("deserializing persisted agent panel navigation history")? - .into_iter() - .take(MAX_RECENTLY_OPENED_ENTRIES) - .flat_map(|entry| match entry { - SerializedRecentOpen::Thread(id) => { - Some(HistoryEntryId::Thread(id.as_str().into())) - } - SerializedRecentOpen::ContextName(file_name) => Some(HistoryEntryId::Context( - contexts_dir().join(file_name).into(), - )), - SerializedRecentOpen::Context(path) => { - Path::new(&path).file_name().map(|file_name| { - HistoryEntryId::Context(contexts_dir().join(file_name).into()) - }) - } - }) - .collect::>(); - Ok(entries) - }) - } - - pub fn push_recently_opened_entry(&mut self, entry: HistoryEntryId, cx: &mut Context) { - self.recently_opened_entries - .retain(|old_entry| old_entry != &entry); - self.recently_opened_entries.push_front(entry); - self.recently_opened_entries - .truncate(MAX_RECENTLY_OPENED_ENTRIES); - self.save_recently_opened_entries(cx); - } - - pub fn remove_recently_opened_thread(&mut self, id: ThreadId, cx: &mut Context) { - self.recently_opened_entries.retain( - |entry| !matches!(entry, HistoryEntryId::Thread(thread_id) if thread_id == &id), - ); - self.save_recently_opened_entries(cx); - } - - pub fn replace_recently_opened_text_thread( - &mut self, - old_path: &Path, - new_path: &Arc, - cx: &mut Context, - ) { - for entry in &mut self.recently_opened_entries { - match entry { - HistoryEntryId::Context(path) if path.as_ref() == old_path => { - *entry = HistoryEntryId::Context(new_path.clone()); - break; - } - _ => {} - } - } - self.save_recently_opened_entries(cx); - } - - pub fn remove_recently_opened_entry(&mut self, entry: &HistoryEntryId, cx: &mut Context) { - self.recently_opened_entries - .retain(|old_entry| old_entry != entry); - self.save_recently_opened_entries(cx); - } -} diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index eb25ddd9bc9402bbecf49750916d677ac1b3a21e..d71279528fa6b1be36ed3b4b6b1f46b4f787751b 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -34,7 +34,6 @@ use crate::{ }; use agent::{ context_store::ContextStore, - history_store::{HistoryEntryId, HistoryStore}, thread_store::{TextThreadStore, ThreadStore}, }; use agent_settings::AgentSettings; @@ -309,7 +308,6 @@ impl ActiveView { pub fn prompt_editor( context_editor: Entity, - history_store: Entity, acp_history_store: Entity, language_registry: Arc, window: &mut Window, @@ -377,18 +375,6 @@ impl ActiveView { }) } ContextEvent::PathChanged { old_path, new_path } => { - history_store.update(cx, |history_store, cx| { - if let Some(old_path) = old_path { - history_store - .replace_recently_opened_text_thread(old_path, new_path, cx); - } else { - history_store.push_recently_opened_entry( - HistoryEntryId::Context(new_path.clone()), - cx, - ); - } - }); - acp_history_store.update(cx, |history_store, cx| { if let Some(old_path) = old_path { history_store @@ -430,7 +416,7 @@ pub struct AgentPanel { language_registry: Arc, thread_store: Entity, acp_history: Entity, - acp_history_store: Entity, + history_store: Entity, context_store: Entity, prompt_store: Option>, inline_assist_context_store: Entity, @@ -438,7 +424,6 @@ pub struct AgentPanel { configuration_subscription: Option, active_view: ActiveView, previous_view: Option, - history_store: Entity, new_thread_menu_handle: PopoverMenuHandle, agent_panel_menu_handle: PopoverMenuHandle, assistant_navigation_menu_handle: PopoverMenuHandle, @@ -571,10 +556,8 @@ impl AgentPanel { let inline_assist_context_store = cx.new(|_cx| ContextStore::new(project.downgrade(), Some(thread_store.downgrade()))); - let history_store = cx.new(|cx| HistoryStore::new(context_store.clone(), [], cx)); - - let acp_history_store = cx.new(|cx| agent2::HistoryStore::new(context_store.clone(), cx)); - let acp_history = cx.new(|cx| AcpThreadHistory::new(acp_history_store.clone(), window, cx)); + let history_store = cx.new(|cx| agent2::HistoryStore::new(context_store.clone(), cx)); + let acp_history = cx.new(|cx| AcpThreadHistory::new(history_store.clone(), window, cx)); cx.subscribe_in( &acp_history, window, @@ -596,14 +579,12 @@ impl AgentPanel { ) .detach(); - cx.observe(&history_store, |_, _, cx| cx.notify()).detach(); - let panel_type = AgentSettings::get_global(cx).default_view; let active_view = match panel_type { DefaultView::Thread => ActiveView::native_agent( fs.clone(), prompt_store.clone(), - acp_history_store.clone(), + history_store.clone(), project.clone(), workspace.clone(), window, @@ -629,7 +610,6 @@ impl AgentPanel { ActiveView::prompt_editor( context_editor, history_store.clone(), - acp_history_store.clone(), language_registry.clone(), window, cx, @@ -695,7 +675,6 @@ impl AgentPanel { configuration_subscription: None, inline_assist_context_store, previous_view: None, - history_store: history_store.clone(), new_thread_menu_handle: PopoverMenuHandle::default(), agent_panel_menu_handle: PopoverMenuHandle::default(), assistant_navigation_menu_handle: PopoverMenuHandle::default(), @@ -706,7 +685,7 @@ impl AgentPanel { pending_serialization: None, onboarding, acp_history, - acp_history_store, + history_store, selected_agent: AgentType::default(), loading: false, } @@ -760,7 +739,7 @@ impl AgentPanel { cx: &mut Context, ) { let Some(thread) = self - .acp_history_store + .history_store .read(cx) .thread_from_session_id(&action.from_session_id) else { @@ -809,7 +788,6 @@ impl AgentPanel { ActiveView::prompt_editor( context_editor.clone(), self.history_store.clone(), - self.acp_history_store.clone(), self.language_registry.clone(), window, cx, @@ -841,7 +819,7 @@ impl AgentPanel { } let loading = self.loading; - let history = self.acp_history_store.clone(); + let history = self.history_store.clone(); cx.spawn_in(window, async move |this, cx| { let ext_agent = match agent_choice { @@ -902,7 +880,7 @@ impl AgentPanel { summarize_thread, workspace.clone(), project, - this.acp_history_store.clone(), + this.history_store.clone(), this.prompt_store.clone(), window, cx, @@ -1000,7 +978,6 @@ impl AgentPanel { ActiveView::prompt_editor( editor, self.history_store.clone(), - self.acp_history_store.clone(), self.language_registry.clone(), window, cx, @@ -1264,11 +1241,6 @@ impl AgentPanel { match &new_view { ActiveView::TextThread { context_editor, .. } => { self.history_store.update(cx, |store, cx| { - if let Some(path) = context_editor.read(cx).context().read(cx).path() { - store.push_recently_opened_entry(HistoryEntryId::Context(path.clone()), cx) - } - }); - self.acp_history_store.update(cx, |store, cx| { if let Some(path) = context_editor.read(cx).context().read(cx).path() { store.push_recently_opened_entry( agent2::HistoryEntryId::TextThread(path.clone()), @@ -1302,7 +1274,7 @@ impl AgentPanel { ) -> ContextMenu { let entries = panel .read(cx) - .acp_history_store + .history_store .read(cx) .recently_opened_entries(cx); @@ -1347,7 +1319,7 @@ impl AgentPanel { move |_window, cx| { panel .update(cx, |this, cx| { - this.acp_history_store.update(cx, |history_store, cx| { + this.history_store.update(cx, |history_store, cx| { history_store.remove_recently_opened_entry(&id, cx); }); }) @@ -2178,10 +2150,7 @@ impl AgentPanel { false } _ => { - let history_is_empty = self.acp_history_store.read(cx).is_empty(cx) - && self - .history_store - .update(cx, |store, cx| store.recent_entries(1, cx).is_empty()); + let history_is_empty = self.history_store.read(cx).is_empty(cx); let has_configured_non_zed_providers = LanguageModelRegistry::read_global(cx) .providers()