Load threads and rule contents
Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
b4d97c437d
commit
98ba2d9acd
7 changed files with 185 additions and 60 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -7,6 +7,7 @@ name = "acp_thread"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"action_log",
|
"action_log",
|
||||||
|
"agent",
|
||||||
"agent-client-protocol",
|
"agent-client-protocol",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"buffer_diff",
|
"buffer_diff",
|
||||||
|
@ -21,6 +22,7 @@ dependencies = [
|
||||||
"markdown",
|
"markdown",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"project",
|
"project",
|
||||||
|
"prompt_store",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -31,6 +33,7 @@ dependencies = [
|
||||||
"ui",
|
"ui",
|
||||||
"url",
|
"url",
|
||||||
"util",
|
"util",
|
||||||
|
"uuid",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ test-support = ["gpui/test-support", "project/test-support"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
action_log.workspace = true
|
action_log.workspace = true
|
||||||
agent-client-protocol.workspace = true
|
agent-client-protocol.workspace = true
|
||||||
|
agent.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
buffer_diff.workspace = true
|
buffer_diff.workspace = true
|
||||||
editor.workspace = true
|
editor.workspace = true
|
||||||
|
@ -28,6 +29,7 @@ language.workspace = true
|
||||||
language_model.workspace = true
|
language_model.workspace = true
|
||||||
markdown.workspace = true
|
markdown.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
|
prompt_store.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
|
@ -36,6 +38,7 @@ terminal.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
|
uuid.workspace = true
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
use agent::ThreadId;
|
||||||
use anyhow::{Context as _, Result, bail};
|
use anyhow::{Context as _, Result, bail};
|
||||||
|
use prompt_store::{PromptId, UserPromptId};
|
||||||
use std::{
|
use std::{
|
||||||
ops::Range,
|
ops::Range,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum MentionUri {
|
pub enum MentionUri {
|
||||||
|
@ -12,9 +15,18 @@ pub enum MentionUri {
|
||||||
name: String,
|
name: String,
|
||||||
line_range: Range<u32>,
|
line_range: Range<u32>,
|
||||||
},
|
},
|
||||||
Thread(String),
|
Thread {
|
||||||
TextThread(PathBuf),
|
id: ThreadId,
|
||||||
Rule(String),
|
name: String,
|
||||||
|
},
|
||||||
|
TextThread {
|
||||||
|
path: PathBuf,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
Rule {
|
||||||
|
id: PromptId,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
Selection {
|
Selection {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
line_range: Range<u32>,
|
line_range: Range<u32>,
|
||||||
|
@ -44,33 +56,42 @@ impl MentionUri {
|
||||||
.context("Parsing line range end")?
|
.context("Parsing line range end")?
|
||||||
.checked_sub(1)
|
.checked_sub(1)
|
||||||
.context("Line numbers should be 1-based")?;
|
.context("Line numbers should be 1-based")?;
|
||||||
let pairs = url.query_pairs().collect::<Vec<_>>();
|
if let Some(name) = single_query_param(&url, "symbol")? {
|
||||||
match pairs.as_slice() {
|
Ok(Self::Symbol {
|
||||||
[] => Ok(Self::Selection {
|
name,
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
line_range,
|
line_range,
|
||||||
}),
|
})
|
||||||
[(k, v)] => {
|
} else {
|
||||||
if k != "symbol" {
|
Ok(Self::Selection {
|
||||||
bail!("invalid query parameter")
|
path: path.into(),
|
||||||
}
|
line_range,
|
||||||
Ok(Self::Symbol {
|
})
|
||||||
name: v.to_string(),
|
|
||||||
path: path.into(),
|
|
||||||
line_range,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => bail!("too many query pairs"),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Self::File(path.into()))
|
Ok(Self::File(path.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"zed" => {
|
"zed" => {
|
||||||
if let Some(thread) = path.strip_prefix("/agent/thread/") {
|
if let Some(thread_id) = path.strip_prefix("/agent/thread/") {
|
||||||
Ok(Self::Thread(thread.into()))
|
let name = single_query_param(&url, "name")?.context("Missing thread name")?;
|
||||||
} else if let Some(rule) = path.strip_prefix("/agent/rule/") {
|
Ok(Self::Thread {
|
||||||
Ok(Self::Rule(rule.into()))
|
id: thread_id.into(),
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
} else if let Some(path) = path.strip_prefix("/agent/text-thread/") {
|
||||||
|
let name = single_query_param(&url, "name")?.context("Missing thread name")?;
|
||||||
|
Ok(Self::TextThread {
|
||||||
|
path: path.into(),
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
} else if let Some(rule_id) = path.strip_prefix("/agent/rule/") {
|
||||||
|
let name = single_query_param(&url, "name")?.context("Missing rule name")?;
|
||||||
|
let rule_id = UserPromptId(rule_id.parse()?);
|
||||||
|
Ok(Self::Rule {
|
||||||
|
id: rule_id.into(),
|
||||||
|
name,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
bail!("invalid zed url: {:?}", input);
|
bail!("invalid zed url: {:?}", input);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +100,7 @@ impl MentionUri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
MentionUri::File(path) => path
|
MentionUri::File(path) => path
|
||||||
.file_name()
|
.file_name()
|
||||||
|
@ -87,9 +108,10 @@ impl MentionUri {
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned(),
|
.into_owned(),
|
||||||
MentionUri::Symbol { name, .. } => name.clone(),
|
MentionUri::Symbol { name, .. } => name.clone(),
|
||||||
MentionUri::Thread(thread) => thread.to_string(),
|
// todo! better names
|
||||||
MentionUri::TextThread(thread) => thread.display().to_string(),
|
MentionUri::Thread { name, .. } => name.clone(),
|
||||||
MentionUri::Rule(rule) => rule.clone(),
|
MentionUri::TextThread { name, .. } => name.clone(),
|
||||||
|
MentionUri::Rule { name, .. } => name.clone(),
|
||||||
MentionUri::Selection {
|
MentionUri::Selection {
|
||||||
path, line_range, ..
|
path, line_range, ..
|
||||||
} => selection_name(path, line_range),
|
} => selection_name(path, line_range),
|
||||||
|
@ -129,19 +151,34 @@ impl MentionUri {
|
||||||
line_range.end + 1,
|
line_range.end + 1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
MentionUri::Thread(thread) => {
|
MentionUri::Thread { name, id } => {
|
||||||
format!("zed:///agent/thread/{}", thread)
|
format!("zed:///agent/thread/{id}?name={name}")
|
||||||
}
|
}
|
||||||
MentionUri::TextThread(path) => {
|
MentionUri::TextThread { path, name } => {
|
||||||
format!("zed:///agent/text-thread/{}", path.display())
|
format!("zed:///agent/text-thread/{}?name={name}", path.display())
|
||||||
}
|
}
|
||||||
MentionUri::Rule(rule) => {
|
MentionUri::Rule { name, id } => {
|
||||||
format!("zed:///agent/rule/{}", rule)
|
format!("zed:///agent/rule/{id}?name={name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn single_query_param(url: &Url, name: &'static str) -> Result<Option<String>> {
|
||||||
|
let pairs = url.query_pairs().collect::<Vec<_>>();
|
||||||
|
match pairs.as_slice() {
|
||||||
|
[] => Ok(None),
|
||||||
|
[(k, v)] => {
|
||||||
|
if k != name {
|
||||||
|
bail!("invalid query parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(v.to_string()))
|
||||||
|
}
|
||||||
|
_ => bail!("too many query pairs"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn selection_name(path: &Path, line_range: &Range<u32>) -> String {
|
pub fn selection_name(path: &Path, line_range: &Range<u32>) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} ({}:{})",
|
"{} ({}:{})",
|
||||||
|
@ -203,10 +240,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_thread_uri() {
|
fn test_parse_thread_uri() {
|
||||||
let thread_uri = "zed:///agent/thread/session123";
|
let thread_uri = "zed:///agent/thread/session123?name=Thread%20name";
|
||||||
let parsed = MentionUri::parse(thread_uri).unwrap();
|
let parsed = MentionUri::parse(thread_uri).unwrap();
|
||||||
match &parsed {
|
match &parsed {
|
||||||
MentionUri::Thread(thread_id) => assert_eq!(thread_id, "session123"),
|
MentionUri::Thread {
|
||||||
|
id: thread_id,
|
||||||
|
name,
|
||||||
|
} => {
|
||||||
|
assert_eq!(thread_id.to_string(), "session123");
|
||||||
|
assert_eq!(name, "Thread name");
|
||||||
|
}
|
||||||
_ => panic!("Expected Thread variant"),
|
_ => panic!("Expected Thread variant"),
|
||||||
}
|
}
|
||||||
assert_eq!(parsed.to_uri(), thread_uri);
|
assert_eq!(parsed.to_uri(), thread_uri);
|
||||||
|
@ -214,10 +257,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_rule_uri() {
|
fn test_parse_rule_uri() {
|
||||||
let rule_uri = "zed:///agent/rule/my_rule";
|
let rule_uri = "zed:///agent/rule/d8694ff2-90d5-4b6f-be33-33c1763acd52?name=Some%20rule";
|
||||||
let parsed = MentionUri::parse(rule_uri).unwrap();
|
let parsed = MentionUri::parse(rule_uri).unwrap();
|
||||||
match &parsed {
|
match &parsed {
|
||||||
MentionUri::Rule(rule) => assert_eq!(rule, "my_rule"),
|
MentionUri::Rule { id, name } => {
|
||||||
|
assert_eq!(id.to_string(), "d8694ff2-90d5-4b6f-be33-33c1763acd52");
|
||||||
|
assert_eq!(name, "Some rule");
|
||||||
|
}
|
||||||
_ => panic!("Expected Rule variant"),
|
_ => panic!("Expected Rule variant"),
|
||||||
}
|
}
|
||||||
assert_eq!(parsed.to_uri(), rule_uri);
|
assert_eq!(parsed.to_uri(), rule_uri);
|
||||||
|
|
|
@ -1209,13 +1209,13 @@ impl AgentMessage {
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
MentionUri::Thread(_session_id) => {
|
MentionUri::Thread { .. } => {
|
||||||
write!(&mut thread_context, "\n{}\n", content).ok();
|
write!(&mut thread_context, "\n{}\n", content).ok();
|
||||||
}
|
}
|
||||||
MentionUri::TextThread(_session_id) => {
|
MentionUri::TextThread { .. } => {
|
||||||
write!(&mut thread_context, "\n{}\n", content).ok();
|
write!(&mut thread_context, "\n{}\n", content).ok();
|
||||||
}
|
}
|
||||||
MentionUri::Rule(_user_prompt_id) => {
|
MentionUri::Rule { .. } => {
|
||||||
write!(
|
write!(
|
||||||
&mut rules_context,
|
&mut rules_context,
|
||||||
"\n{}",
|
"\n{}",
|
||||||
|
|
|
@ -4,10 +4,10 @@ use std::sync::Arc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use acp_thread::{MentionUri, selection_name};
|
use acp_thread::{MentionUri, selection_name};
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use editor::display_map::CreaseId;
|
use editor::display_map::CreaseId;
|
||||||
use editor::{AnchorRangeExt, CompletionProvider, Editor, ExcerptId, ToOffset as _, ToPoint};
|
use editor::{CompletionProvider, Editor, ExcerptId, ToOffset as _};
|
||||||
use file_icons::FileIcons;
|
use file_icons::FileIcons;
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||||
|
@ -21,7 +21,7 @@ use project::{
|
||||||
};
|
};
|
||||||
use prompt_store::PromptStore;
|
use prompt_store::PromptStore;
|
||||||
use rope::Point;
|
use rope::Point;
|
||||||
use text::{Anchor, ToPoint as _};
|
use text::{Anchor, OffsetRangeExt as _, ToPoint as _};
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
|
@ -59,14 +59,16 @@ impl MentionSet {
|
||||||
pub fn contents(
|
pub fn contents(
|
||||||
&self,
|
&self,
|
||||||
project: Entity<Project>,
|
project: Entity<Project>,
|
||||||
|
thread_store: Entity<ThreadStore>,
|
||||||
|
text_thread_store: Entity<TextThreadStore>,
|
||||||
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Task<Result<HashMap<CreaseId, Mention>>> {
|
) -> Task<Result<HashMap<CreaseId, Mention>>> {
|
||||||
let contents = self
|
let contents = self
|
||||||
.uri_by_crease_id
|
.uri_by_crease_id
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(crease_id, uri)| match uri {
|
.map(|(&crease_id, uri)| match uri {
|
||||||
MentionUri::File(path) => {
|
MentionUri::File(path) => {
|
||||||
let crease_id = *crease_id;
|
|
||||||
let uri = uri.clone();
|
let uri = uri.clone();
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
let buffer_task = project.update(cx, |project, cx| {
|
let buffer_task = project.update(cx, |project, cx| {
|
||||||
|
@ -89,7 +91,6 @@ impl MentionSet {
|
||||||
| MentionUri::Selection {
|
| MentionUri::Selection {
|
||||||
path, line_range, ..
|
path, line_range, ..
|
||||||
} => {
|
} => {
|
||||||
let crease_id = *crease_id;
|
|
||||||
let uri = uri.clone();
|
let uri = uri.clone();
|
||||||
let path_buf = path.clone();
|
let path_buf = path.clone();
|
||||||
let line_range = line_range.clone();
|
let line_range = line_range.clone();
|
||||||
|
@ -118,9 +119,44 @@ impl MentionSet {
|
||||||
anyhow::Ok((crease_id, Mention { uri, content }))
|
anyhow::Ok((crease_id, Mention { uri, content }))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
MentionUri::Thread(_) => todo!(),
|
MentionUri::Thread { id: thread_id, .. } => {
|
||||||
MentionUri::TextThread(path_buf) => todo!(),
|
let open_task = thread_store.update(cx, |thread_store, cx| {
|
||||||
MentionUri::Rule(_) => todo!(),
|
thread_store.open_thread(&thread_id, window, cx)
|
||||||
|
});
|
||||||
|
|
||||||
|
let uri = uri.clone();
|
||||||
|
cx.spawn(async move |cx| {
|
||||||
|
let thread = open_task.await?;
|
||||||
|
let content = thread.read_with(cx, |thread, _cx| {
|
||||||
|
thread.latest_detailed_summary_or_text().to_string()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
anyhow::Ok((crease_id, Mention { uri, content }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
MentionUri::TextThread { path, .. } => {
|
||||||
|
let context = text_thread_store.update(cx, |text_thread_store, cx| {
|
||||||
|
text_thread_store.open_local_context(path.as_path().into(), cx)
|
||||||
|
});
|
||||||
|
let uri = uri.clone();
|
||||||
|
cx.spawn(async move |cx| {
|
||||||
|
let context = context.await?;
|
||||||
|
let xml = context.update(cx, |context, cx| context.to_xml(cx))?;
|
||||||
|
anyhow::Ok((crease_id, Mention { uri, content: xml }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
MentionUri::Rule { id: prompt_id, .. } => {
|
||||||
|
let Some(prompt_store) = thread_store.read(cx).prompt_store().clone() else {
|
||||||
|
return Task::ready(Err(anyhow!("missing prompt store")));
|
||||||
|
};
|
||||||
|
let text_task = prompt_store.read(cx).load(prompt_id.clone(), cx);
|
||||||
|
let uri = uri.clone();
|
||||||
|
cx.spawn(async move |_| {
|
||||||
|
// TODO: report load errors instead of just logging
|
||||||
|
let text = text_task.await?;
|
||||||
|
anyhow::Ok((crease_id, Mention { uri, content: text }))
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -434,7 +470,12 @@ impl ContextPickerCompletionProvider {
|
||||||
file.path().to_path_buf()
|
file.path().to_path_buf()
|
||||||
});
|
});
|
||||||
|
|
||||||
let point_range = range.to_point(&snapshot);
|
let point_range = snapshot
|
||||||
|
.as_singleton()
|
||||||
|
.map(|(_, _, snapshot)| {
|
||||||
|
selection_range.to_point(&snapshot)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
let line_range = point_range.start.row..point_range.end.row;
|
let line_range = point_range.start.row..point_range.end.row;
|
||||||
let crease = crate::context_picker::crease_for_mention(
|
let crease = crate::context_picker::crease_for_mention(
|
||||||
selection_name(&path, &line_range).into(),
|
selection_name(&path, &line_range).into(),
|
||||||
|
@ -505,8 +546,14 @@ impl ContextPickerCompletionProvider {
|
||||||
};
|
};
|
||||||
|
|
||||||
let uri = match &thread_entry {
|
let uri = match &thread_entry {
|
||||||
ThreadContextEntry::Thread { id, .. } => MentionUri::Thread(id.to_string()),
|
ThreadContextEntry::Thread { id, title } => MentionUri::Thread {
|
||||||
ThreadContextEntry::Context { path, .. } => MentionUri::TextThread(path.to_path_buf()),
|
id: id.clone(),
|
||||||
|
name: title.to_string(),
|
||||||
|
},
|
||||||
|
ThreadContextEntry::Context { path, title } => MentionUri::TextThread {
|
||||||
|
path: path.to_path_buf(),
|
||||||
|
name: title.to_string(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let new_text = format!("{} ", uri.to_link());
|
let new_text = format!("{} ", uri.to_link());
|
||||||
|
|
||||||
|
@ -533,26 +580,29 @@ impl ContextPickerCompletionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completion_for_rules(
|
fn completion_for_rules(
|
||||||
rules: RulesContextEntry,
|
rule: RulesContextEntry,
|
||||||
excerpt_id: ExcerptId,
|
excerpt_id: ExcerptId,
|
||||||
source_range: Range<Anchor>,
|
source_range: Range<Anchor>,
|
||||||
editor: Entity<Editor>,
|
editor: Entity<Editor>,
|
||||||
mention_set: Arc<Mutex<MentionSet>>,
|
mention_set: Arc<Mutex<MentionSet>>,
|
||||||
) -> Completion {
|
) -> Completion {
|
||||||
let uri = MentionUri::Rule(rules.prompt_id.0.to_string());
|
let uri = MentionUri::Rule {
|
||||||
|
id: rule.prompt_id.into(),
|
||||||
|
name: rule.title.to_string(),
|
||||||
|
};
|
||||||
let new_text = format!("{} ", uri.to_link());
|
let new_text = format!("{} ", uri.to_link());
|
||||||
let new_text_len = new_text.len();
|
let new_text_len = new_text.len();
|
||||||
Completion {
|
Completion {
|
||||||
replace_range: source_range.clone(),
|
replace_range: source_range.clone(),
|
||||||
new_text,
|
new_text,
|
||||||
label: CodeLabel::plain(rules.title.to_string(), None),
|
label: CodeLabel::plain(rule.title.to_string(), None),
|
||||||
documentation: None,
|
documentation: None,
|
||||||
insert_text_mode: None,
|
insert_text_mode: None,
|
||||||
source: project::CompletionSource::Custom,
|
source: project::CompletionSource::Custom,
|
||||||
icon_path: Some(RULES_ICON.path().into()),
|
icon_path: Some(RULES_ICON.path().into()),
|
||||||
confirm: Some(confirm_completion_callback(
|
confirm: Some(confirm_completion_callback(
|
||||||
RULES_ICON.path().into(),
|
RULES_ICON.path().into(),
|
||||||
rules.title.clone(),
|
rule.title.clone(),
|
||||||
excerpt_id,
|
excerpt_id,
|
||||||
source_range.start,
|
source_range.start,
|
||||||
new_text_len - 1,
|
new_text_len - 1,
|
||||||
|
@ -657,8 +707,7 @@ impl ContextPickerCompletionProvider {
|
||||||
file_name.to_string()
|
file_name.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
|
let label = CodeLabel::plain(symbol.name.clone(), None);
|
||||||
let mut label = CodeLabel::plain(symbol.name.clone(), None);
|
|
||||||
|
|
||||||
let uri = MentionUri::Symbol {
|
let uri = MentionUri::Symbol {
|
||||||
path: full_path.into(),
|
path: full_path.into(),
|
||||||
|
@ -754,8 +803,8 @@ impl CompletionProvider for ContextPickerCompletionProvider {
|
||||||
MentionUri::File(path) => {
|
MentionUri::File(path) => {
|
||||||
excluded_paths.insert(path.clone());
|
excluded_paths.insert(path.clone());
|
||||||
}
|
}
|
||||||
MentionUri::Thread(thread) => {
|
MentionUri::Thread { id, .. } => {
|
||||||
excluded_threads.insert(thread.as_str().into());
|
excluded_threads.insert(id.clone());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ pub struct AcpThreadView {
|
||||||
agent: Rc<dyn AgentServer>,
|
agent: Rc<dyn AgentServer>,
|
||||||
workspace: WeakEntity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
project: Entity<Project>,
|
project: Entity<Project>,
|
||||||
|
thread_store: WeakEntity<ThreadStore>,
|
||||||
|
text_thread_store: WeakEntity<TextThreadStore>,
|
||||||
thread_state: ThreadState,
|
thread_state: ThreadState,
|
||||||
diff_editors: HashMap<EntityId, Entity<Editor>>,
|
diff_editors: HashMap<EntityId, Entity<Editor>>,
|
||||||
terminal_views: HashMap<EntityId, Entity<TerminalView>>,
|
terminal_views: HashMap<EntityId, Entity<TerminalView>>,
|
||||||
|
@ -189,6 +191,8 @@ impl AcpThreadView {
|
||||||
agent: agent.clone(),
|
agent: agent.clone(),
|
||||||
workspace: workspace.clone(),
|
workspace: workspace.clone(),
|
||||||
project: project.clone(),
|
project: project.clone(),
|
||||||
|
thread_store,
|
||||||
|
text_thread_store,
|
||||||
thread_state: Self::initial_state(agent, workspace, project, window, cx),
|
thread_state: Self::initial_state(agent, workspace, project, window, cx),
|
||||||
message_editor,
|
message_editor,
|
||||||
message_set_from_history: None,
|
message_set_from_history: None,
|
||||||
|
@ -383,7 +387,17 @@ impl AcpThreadView {
|
||||||
let mut chunks: Vec<acp::ContentBlock> = Vec::new();
|
let mut chunks: Vec<acp::ContentBlock> = Vec::new();
|
||||||
let project = self.project.clone();
|
let project = self.project.clone();
|
||||||
|
|
||||||
let contents = self.mention_set.lock().contents(project, cx);
|
let Some(thread_store) = self.thread_store.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(text_thread_store) = self.text_thread_store.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let contents =
|
||||||
|
self.mention_set
|
||||||
|
.lock()
|
||||||
|
.contents(project, thread_store, text_thread_store, window, cx);
|
||||||
|
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
let contents = match contents.await {
|
let contents = match contents.await {
|
||||||
|
|
|
@ -90,6 +90,16 @@ impl From<Uuid> for UserPromptId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo! remove me
|
||||||
|
impl std::fmt::Display for PromptId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
PromptId::User { uuid } => write!(f, "{}", uuid.0),
|
||||||
|
PromptId::EditWorkflow => write!(f, "Edit workflow"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PromptStore {
|
pub struct PromptStore {
|
||||||
env: heed::Env,
|
env: heed::Env,
|
||||||
metadata_cache: RwLock<MetadataCache>,
|
metadata_cache: RwLock<MetadataCache>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue