Threads and rule support
Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
e2973998ad
commit
91e22597a8
5 changed files with 68 additions and 98 deletions
|
@ -1,4 +1,3 @@
|
|||
use agent_client_protocol as acp;
|
||||
use anyhow::{Result, bail};
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -6,7 +5,8 @@ use std::path::PathBuf;
|
|||
pub enum MentionUri {
|
||||
File(PathBuf),
|
||||
Symbol(PathBuf, String),
|
||||
Thread(acp::SessionId),
|
||||
Thread(String),
|
||||
TextThread(PathBuf),
|
||||
Rule(String),
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ impl MentionUri {
|
|||
}
|
||||
"zed" => {
|
||||
if let Some(thread) = path.strip_prefix("/agent/thread/") {
|
||||
Ok(Self::Thread(acp::SessionId(thread.into())))
|
||||
Ok(Self::Thread(thread.into()))
|
||||
} else if let Some(rule) = path.strip_prefix("/agent/rule/") {
|
||||
Ok(Self::Rule(rule.into()))
|
||||
} else {
|
||||
|
@ -40,6 +40,7 @@ impl MentionUri {
|
|||
MentionUri::File(path) => path.file_name().unwrap().to_string_lossy().into_owned(),
|
||||
MentionUri::Symbol(_path, name) => name.clone(),
|
||||
MentionUri::Thread(thread) => thread.to_string(),
|
||||
MentionUri::TextThread(thread) => thread.display().to_string(),
|
||||
MentionUri::Rule(rule) => rule.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +61,10 @@ impl MentionUri {
|
|||
format!("file://{}#{}", path.display(), name)
|
||||
}
|
||||
MentionUri::Thread(thread) => {
|
||||
format!("zed:///agent/thread/{}", thread.0)
|
||||
format!("zed:///agent/thread/{}", thread)
|
||||
}
|
||||
MentionUri::TextThread(path) => {
|
||||
format!("zed:///agent/text-thread/{}", path.display())
|
||||
}
|
||||
MentionUri::Rule(rule) => {
|
||||
format!("zed:///agent/rule/{}", rule)
|
||||
|
@ -100,7 +104,7 @@ mod tests {
|
|||
let thread_uri = "zed:///agent/thread/session123";
|
||||
let parsed = MentionUri::parse(thread_uri).unwrap();
|
||||
match &parsed {
|
||||
MentionUri::Thread(session_id) => assert_eq!(session_id.0.as_ref(), "session123"),
|
||||
MentionUri::Thread(thread_id) => assert_eq!(thread_id, "session123"),
|
||||
_ => panic!("Expected Thread variant"),
|
||||
}
|
||||
assert_eq!(parsed.to_uri(), thread_uri);
|
||||
|
|
|
@ -1196,6 +1196,9 @@ impl AgentMessage {
|
|||
MentionUri::Thread(_session_id) => {
|
||||
write!(&mut thread_context, "\n{}\n", content).ok();
|
||||
}
|
||||
MentionUri::TextThread(_session_id) => {
|
||||
write!(&mut thread_context, "\n{}\n", content).ok();
|
||||
}
|
||||
MentionUri::Rule(_user_prompt_id) => {
|
||||
write!(
|
||||
&mut rules_context,
|
||||
|
|
|
@ -306,8 +306,8 @@ fn search(
|
|||
pub struct ContextPickerCompletionProvider {
|
||||
mention_set: Arc<Mutex<MentionSet>>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
thread_store: Option<WeakEntity<ThreadStore>>,
|
||||
text_thread_store: Option<WeakEntity<TextThreadStore>>,
|
||||
thread_store: WeakEntity<ThreadStore>,
|
||||
text_thread_store: WeakEntity<TextThreadStore>,
|
||||
editor: WeakEntity<Editor>,
|
||||
}
|
||||
|
||||
|
@ -315,8 +315,8 @@ impl ContextPickerCompletionProvider {
|
|||
pub fn new(
|
||||
mention_set: Arc<Mutex<MentionSet>>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
thread_store: Option<WeakEntity<ThreadStore>>,
|
||||
text_thread_store: Option<WeakEntity<TextThreadStore>>,
|
||||
thread_store: WeakEntity<ThreadStore>,
|
||||
text_thread_store: WeakEntity<TextThreadStore>,
|
||||
editor: WeakEntity<Editor>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -474,77 +474,39 @@ impl ContextPickerCompletionProvider {
|
|||
recent: bool,
|
||||
editor: Entity<Editor>,
|
||||
mention_set: Arc<Mutex<MentionSet>>,
|
||||
thread_store: Entity<ThreadStore>,
|
||||
text_thread_store: Entity<TextThreadStore>,
|
||||
) -> Completion {
|
||||
todo!();
|
||||
// let icon_for_completion = if recent {
|
||||
// IconName::HistoryRerun
|
||||
// } else {
|
||||
// IconName::Thread
|
||||
// };
|
||||
let icon_for_completion = if recent {
|
||||
IconName::HistoryRerun
|
||||
} else {
|
||||
IconName::Thread
|
||||
};
|
||||
|
||||
// let new_text = format!("{} ", MentionUri::Thread(thread_id));
|
||||
let uri = match &thread_entry {
|
||||
ThreadContextEntry::Thread { id, .. } => MentionUri::Thread(id.to_string()),
|
||||
ThreadContextEntry::Context { path, .. } => MentionUri::TextThread(path.to_path_buf()),
|
||||
};
|
||||
let new_text = format!("{} ", uri.to_link());
|
||||
|
||||
// let new_text_len = new_text.len();
|
||||
// Completion {
|
||||
// replace_range: source_range.clone(),
|
||||
// new_text,
|
||||
// label: CodeLabel::plain(thread_entry.title().to_string(), None),
|
||||
// documentation: None,
|
||||
// insert_text_mode: None,
|
||||
// source: project::CompletionSource::Custom,
|
||||
// icon_path: Some(icon_for_completion.path().into()),
|
||||
// confirm: Some(confirm_completion_callback(
|
||||
// IconName::Thread.path().into(),
|
||||
// thread_entry.title().clone(),
|
||||
// excerpt_id,
|
||||
// source_range.start,
|
||||
// new_text_len - 1,
|
||||
// editor.clone(),
|
||||
// context_store.clone(),
|
||||
// move |window, cx| match &thread_entry {
|
||||
// ThreadContextEntry::Thread { id, .. } => {
|
||||
// let thread_id = id.clone();
|
||||
// let context_store = context_store.clone();
|
||||
// let thread_store = thread_store.clone();
|
||||
// window.spawn::<_, Option<_>>(cx, async move |cx| {
|
||||
// let thread: Entity<Thread> = thread_store
|
||||
// .update_in(cx, |thread_store, window, cx| {
|
||||
// thread_store.open_thread(&thread_id, window, cx)
|
||||
// })
|
||||
// .ok()?
|
||||
// .await
|
||||
// .log_err()?;
|
||||
// let context = context_store
|
||||
// .update(cx, |context_store, cx| {
|
||||
// context_store.add_thread(thread, false, cx)
|
||||
// })
|
||||
// .ok()??;
|
||||
// Some(context)
|
||||
// })
|
||||
// }
|
||||
// ThreadContextEntry::Context { path, .. } => {
|
||||
// let path = path.clone();
|
||||
// let context_store = context_store.clone();
|
||||
// let text_thread_store = text_thread_store.clone();
|
||||
// cx.spawn::<_, Option<_>>(async move |cx| {
|
||||
// let thread = text_thread_store
|
||||
// .update(cx, |store, cx| store.open_local_context(path, cx))
|
||||
// .ok()?
|
||||
// .await
|
||||
// .log_err()?;
|
||||
// let context = context_store
|
||||
// .update(cx, |context_store, cx| {
|
||||
// context_store.add_text_thread(thread, false, cx)
|
||||
// })
|
||||
// .ok()??;
|
||||
// Some(context)
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// )),
|
||||
// }
|
||||
let new_text_len = new_text.len();
|
||||
Completion {
|
||||
replace_range: source_range.clone(),
|
||||
new_text,
|
||||
label: CodeLabel::plain(thread_entry.title().to_string(), None),
|
||||
documentation: None,
|
||||
insert_text_mode: None,
|
||||
source: project::CompletionSource::Custom,
|
||||
icon_path: Some(icon_for_completion.path().into()),
|
||||
confirm: Some(confirm_completion_callback(
|
||||
IconName::Thread.path().into(),
|
||||
thread_entry.title().clone(),
|
||||
excerpt_id,
|
||||
source_range.start,
|
||||
new_text_len - 1,
|
||||
editor.clone(),
|
||||
mention_set,
|
||||
uri,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn completion_for_rules(
|
||||
|
@ -555,7 +517,7 @@ impl ContextPickerCompletionProvider {
|
|||
mention_set: Arc<Mutex<MentionSet>>,
|
||||
) -> Completion {
|
||||
let uri = MentionUri::Rule(rules.prompt_id.0.to_string());
|
||||
let new_text = uri.to_link();
|
||||
let new_text = format!("{} ", uri.to_link());
|
||||
let new_text_len = new_text.len();
|
||||
Completion {
|
||||
replace_range: source_range.clone(),
|
||||
|
@ -769,7 +731,7 @@ impl CompletionProvider for ContextPickerCompletionProvider {
|
|||
excluded_paths.insert(path.clone());
|
||||
}
|
||||
MentionUri::Thread(thread) => {
|
||||
excluded_threads.insert(thread.0.as_ref().into());
|
||||
excluded_threads.insert(thread.as_str().into());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -850,21 +812,14 @@ impl CompletionProvider for ContextPickerCompletionProvider {
|
|||
|
||||
Match::Thread(ThreadMatch {
|
||||
thread, is_recent, ..
|
||||
}) => {
|
||||
let thread_store = thread_store.as_ref().and_then(|t| t.upgrade())?;
|
||||
let text_thread_store =
|
||||
text_thread_store.as_ref().and_then(|t| t.upgrade())?;
|
||||
Some(Self::completion_for_thread(
|
||||
thread,
|
||||
excerpt_id,
|
||||
source_range.clone(),
|
||||
is_recent,
|
||||
editor.clone(),
|
||||
mention_set.clone(),
|
||||
thread_store,
|
||||
text_thread_store,
|
||||
))
|
||||
}
|
||||
}) => Some(Self::completion_for_thread(
|
||||
thread,
|
||||
excerpt_id,
|
||||
source_range.clone(),
|
||||
is_recent,
|
||||
editor.clone(),
|
||||
mention_set.clone(),
|
||||
)),
|
||||
|
||||
Match::Rules(user_rules) => Some(Self::completion_for_rules(
|
||||
user_rules,
|
||||
|
|
|
@ -4,6 +4,7 @@ use acp_thread::{
|
|||
};
|
||||
use acp_thread::{AgentConnection, Plan};
|
||||
use action_log::ActionLog;
|
||||
use agent::{TextThreadStore, ThreadStore};
|
||||
use agent_client_protocol as acp;
|
||||
use agent_servers::AgentServer;
|
||||
use agent_settings::{AgentSettings, NotifyWhenAgentWaiting};
|
||||
|
@ -104,6 +105,8 @@ impl AcpThreadView {
|
|||
agent: Rc<dyn AgentServer>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
thread_store: WeakEntity<ThreadStore>,
|
||||
text_thread_store: WeaksEntity<TextThreadStore>,
|
||||
message_history: Rc<RefCell<MessageHistory<Vec<acp::ContentBlock>>>>,
|
||||
min_lines: usize,
|
||||
max_lines: Option<usize>,
|
||||
|
@ -141,11 +144,9 @@ impl AcpThreadView {
|
|||
editor.set_completion_provider(Some(Rc::new(ContextPickerCompletionProvider::new(
|
||||
mention_set.clone(),
|
||||
workspace.clone(),
|
||||
// todo! provide thread stores
|
||||
None,
|
||||
None,
|
||||
thread_store.clone(),
|
||||
text_thread_store.clone(),
|
||||
cx.weak_entity(),
|
||||
// None,
|
||||
))));
|
||||
editor.set_context_menu_options(ContextMenuOptions {
|
||||
min_entries_visible: 12,
|
||||
|
@ -3579,6 +3580,8 @@ mod tests {
|
|||
Rc::new(agent),
|
||||
workspace.downgrade(),
|
||||
project,
|
||||
WeakEntity::new_invalid(),
|
||||
WeakEntity::new_invalid(),
|
||||
Rc::new(RefCell::new(MessageHistory::default())),
|
||||
1,
|
||||
None,
|
||||
|
|
|
@ -924,6 +924,9 @@ impl AgentPanel {
|
|||
agent: crate::ExternalAgent,
|
||||
}
|
||||
|
||||
let thread_store = self.thread_store.clone();
|
||||
let text_thread_store = self.context_store.clone();
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let server: Rc<dyn AgentServer> = match agent_choice {
|
||||
Some(agent) => {
|
||||
|
@ -962,6 +965,8 @@ impl AgentPanel {
|
|||
server,
|
||||
workspace.clone(),
|
||||
project,
|
||||
thread_store.clone(),
|
||||
text_thread_store.clone(),
|
||||
message_history,
|
||||
MIN_EDITOR_LINES,
|
||||
Some(MAX_EDITOR_LINES),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue