ACP history mentions (#36551)

- **TEMP**
- **Update @-mentions to use new history**

Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2025-08-20 00:25:07 -06:00 committed by GitHub
parent 159b5e9fb5
commit 5d2bb2466e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 581 additions and 392 deletions

View file

@ -3,8 +3,9 @@ use crate::{
context_picker::fetch_context_picker::fetch_url_content,
};
use acp_thread::{MentionUri, selection_name};
use agent::{TextThreadStore, ThreadId, ThreadStore};
use agent_client_protocol as acp;
use agent_servers::AgentServer;
use agent2::HistoryStore;
use anyhow::{Context as _, Result, anyhow};
use assistant_slash_commands::codeblock_fence_for_path;
use collections::{HashMap, HashSet};
@ -27,6 +28,7 @@ use gpui::{
use language::{Buffer, Language};
use language_model::LanguageModelImage;
use project::{Project, ProjectPath, Worktree};
use prompt_store::PromptStore;
use rope::Point;
use settings::Settings;
use std::{
@ -59,8 +61,8 @@ pub struct MessageEditor {
editor: Entity<Editor>,
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
thread_store: Entity<ThreadStore>,
text_thread_store: Entity<TextThreadStore>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
prevent_slash_commands: bool,
_subscriptions: Vec<Subscription>,
_parse_slash_command_task: Task<()>,
@ -79,8 +81,8 @@ impl MessageEditor {
pub fn new(
workspace: WeakEntity<Workspace>,
project: Entity<Project>,
thread_store: Entity<ThreadStore>,
text_thread_store: Entity<TextThreadStore>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
placeholder: impl Into<Arc<str>>,
prevent_slash_commands: bool,
mode: EditorMode,
@ -95,10 +97,10 @@ impl MessageEditor {
None,
);
let completion_provider = ContextPickerCompletionProvider::new(
workspace.clone(),
thread_store.downgrade(),
text_thread_store.downgrade(),
cx.weak_entity(),
workspace.clone(),
history_store.clone(),
prompt_store.clone(),
);
let semantics_provider = Rc::new(SlashCommandSemanticsProvider {
range: Cell::new(None),
@ -152,9 +154,9 @@ impl MessageEditor {
editor,
project,
mention_set,
thread_store,
text_thread_store,
workspace,
history_store,
prompt_store,
prevent_slash_commands,
_subscriptions: subscriptions,
_parse_slash_command_task: Task::ready(()),
@ -175,23 +177,12 @@ impl MessageEditor {
self.editor.read(cx).is_empty(cx)
}
pub fn mentioned_path_and_threads(&self) -> (HashSet<PathBuf>, HashSet<ThreadId>) {
let mut excluded_paths = HashSet::default();
let mut excluded_threads = HashSet::default();
for uri in self.mention_set.uri_by_crease_id.values() {
match uri {
MentionUri::File { abs_path, .. } => {
excluded_paths.insert(abs_path.clone());
}
MentionUri::Thread { id, .. } => {
excluded_threads.insert(id.clone());
}
_ => {}
}
}
(excluded_paths, excluded_threads)
pub fn mentions(&self) -> HashSet<MentionUri> {
self.mention_set
.uri_by_crease_id
.values()
.cloned()
.collect()
}
pub fn confirm_completion(
@ -529,7 +520,7 @@ impl MessageEditor {
&mut self,
crease_id: CreaseId,
anchor: Anchor,
id: ThreadId,
id: acp::SessionId,
name: String,
window: &mut Window,
cx: &mut Context<Self>,
@ -538,17 +529,25 @@ impl MessageEditor {
id: id.clone(),
name,
};
let open_task = self.thread_store.update(cx, |thread_store, cx| {
thread_store.open_thread(&id, window, cx)
let server = Rc::new(agent2::NativeAgentServer::new(
self.project.read(cx).fs().clone(),
self.history_store.clone(),
));
let connection = server.connect(Path::new(""), &self.project, cx);
let load_summary = cx.spawn({
let id = id.clone();
async move |_, cx| {
let agent = connection.await?;
let agent = agent.downcast::<agent2::NativeAgentConnection>().unwrap();
let summary = agent
.0
.update(cx, |agent, cx| agent.thread_summary(id, cx))?
.await?;
anyhow::Ok(summary)
}
});
let task = cx
.spawn(async move |_, cx| {
let thread = open_task.await.map_err(|e| e.to_string())?;
let content = thread
.read_with(cx, |thread, _cx| thread.latest_detailed_summary_or_text())
.map_err(|e| e.to_string())?;
Ok(content)
})
.spawn(async move |_, _| load_summary.await.map_err(|e| format!("{e}")))
.shared();
self.mention_set.insert_thread(id.clone(), task.clone());
@ -590,8 +589,8 @@ impl MessageEditor {
path: path.clone(),
name,
};
let context = self.text_thread_store.update(cx, |text_thread_store, cx| {
text_thread_store.open_local_context(path.as_path().into(), cx)
let context = self.history_store.update(cx, |text_thread_store, cx| {
text_thread_store.load_text_thread(path.as_path().into(), cx)
});
let task = cx
.spawn(async move |_, cx| {
@ -637,7 +636,7 @@ impl MessageEditor {
) -> Task<Result<Vec<acp::ContentBlock>>> {
let contents =
self.mention_set
.contents(self.project.clone(), self.thread_store.clone(), window, cx);
.contents(&self.project, self.prompt_store.as_ref(), window, cx);
let editor = self.editor.clone();
let prevent_slash_commands = self.prevent_slash_commands;
@ -1316,7 +1315,7 @@ pub struct MentionSet {
uri_by_crease_id: HashMap<CreaseId, MentionUri>,
fetch_results: HashMap<Url, Shared<Task<Result<String, String>>>>,
images: HashMap<CreaseId, Shared<Task<Result<MentionImage, String>>>>,
thread_summaries: HashMap<ThreadId, Shared<Task<Result<SharedString, String>>>>,
thread_summaries: HashMap<acp::SessionId, Shared<Task<Result<SharedString, String>>>>,
text_thread_summaries: HashMap<PathBuf, Shared<Task<Result<String, String>>>>,
directories: HashMap<PathBuf, Shared<Task<Result<String, String>>>>,
}
@ -1338,7 +1337,11 @@ impl MentionSet {
self.images.insert(crease_id, task);
}
fn insert_thread(&mut self, id: ThreadId, task: Shared<Task<Result<SharedString, String>>>) {
fn insert_thread(
&mut self,
id: acp::SessionId,
task: Shared<Task<Result<SharedString, String>>>,
) {
self.thread_summaries.insert(id, task);
}
@ -1358,8 +1361,8 @@ impl MentionSet {
pub fn contents(
&self,
project: Entity<Project>,
thread_store: Entity<ThreadStore>,
project: &Entity<Project>,
prompt_store: Option<&Entity<PromptStore>>,
_window: &mut Window,
cx: &mut App,
) -> Task<Result<HashMap<CreaseId, Mention>>> {
@ -1484,8 +1487,7 @@ impl MentionSet {
})
}
MentionUri::Rule { id: prompt_id, .. } => {
let Some(prompt_store) = thread_store.read(cx).prompt_store().clone()
else {
let Some(prompt_store) = prompt_store else {
return Task::ready(Err(anyhow!("missing prompt store")));
};
let text_task = prompt_store.read(cx).load(*prompt_id, cx);
@ -1678,8 +1680,9 @@ impl Addon for MessageEditorAddon {
mod tests {
use std::{ops::Range, path::Path, sync::Arc};
use agent::{TextThreadStore, ThreadStore};
use agent_client_protocol as acp;
use agent2::HistoryStore;
use assistant_context::ContextStore;
use editor::{AnchorRangeExt as _, Editor, EditorMode};
use fs::FakeFs;
use futures::StreamExt as _;
@ -1710,16 +1713,16 @@ mod tests {
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let thread_store = cx.new(|cx| ThreadStore::fake(project.clone(), cx));
let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
let message_editor = cx.update(|window, cx| {
cx.new(|cx| {
MessageEditor::new(
workspace.downgrade(),
project.clone(),
thread_store.clone(),
text_thread_store.clone(),
history_store.clone(),
None,
"Test",
false,
EditorMode::AutoHeight {
@ -1908,8 +1911,8 @@ mod tests {
opened_editors.push(buffer);
}
let thread_store = cx.new(|cx| ThreadStore::fake(project.clone(), cx));
let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
let (message_editor, editor) = workspace.update_in(&mut cx, |workspace, window, cx| {
let workspace_handle = cx.weak_entity();
@ -1917,8 +1920,8 @@ mod tests {
MessageEditor::new(
workspace_handle,
project.clone(),
thread_store.clone(),
text_thread_store.clone(),
history_store.clone(),
None,
"Test",
false,
EditorMode::AutoHeight {
@ -2011,12 +2014,9 @@ mod tests {
let contents = message_editor
.update_in(&mut cx, |message_editor, window, cx| {
message_editor.mention_set().contents(
project.clone(),
thread_store.clone(),
window,
cx,
)
message_editor
.mention_set()
.contents(&project, None, window, cx)
})
.await
.unwrap()
@ -2066,12 +2066,9 @@ mod tests {
let contents = message_editor
.update_in(&mut cx, |message_editor, window, cx| {
message_editor.mention_set().contents(
project.clone(),
thread_store.clone(),
window,
cx,
)
message_editor
.mention_set()
.contents(&project, None, window, cx)
})
.await
.unwrap()
@ -2181,7 +2178,7 @@ mod tests {
.update_in(&mut cx, |message_editor, window, cx| {
message_editor
.mention_set()
.contents(project.clone(), thread_store, window, cx)
.contents(&project, None, window, cx)
})
.await
.unwrap()