Allow attaching text threads as context (#29947)

Release Notes:

- N/A

---------

Co-authored-by: Michael Sloan <mgsloan@gmail.com>
This commit is contained in:
Max Brunsfeld 2025-05-05 13:59:21 -07:00 committed by GitHub
parent 7f868a2eff
commit dd79c29af9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 784 additions and 245 deletions

View file

@ -6,7 +6,7 @@ use crate::thread::{
LastRestoreCheckpoint, MessageId, MessageSegment, Thread, ThreadError, ThreadEvent,
ThreadFeedback,
};
use crate::thread_store::{RulesLoadingError, ThreadStore};
use crate::thread_store::{RulesLoadingError, TextThreadStore, ThreadStore};
use crate::tool_use::{PendingToolUseStatus, ToolUse};
use crate::ui::{
AddedContext, AgentNotification, AgentNotificationEvent, AnimatedLabel, ContextPill,
@ -56,6 +56,7 @@ pub struct ActiveThread {
context_store: Entity<ContextStore>,
language_registry: Arc<LanguageRegistry>,
thread_store: Entity<ThreadStore>,
text_thread_store: Entity<TextThreadStore>,
thread: Entity<Thread>,
workspace: WeakEntity<Workspace>,
save_thread_task: Option<Task<()>>,
@ -719,6 +720,15 @@ fn open_markdown_link(
});
}
}),
Some(MentionLink::TextThread(path)) => workspace.update(cx, |workspace, cx| {
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
panel.update(cx, |panel, cx| {
panel
.open_saved_prompt_editor(path, window, cx)
.detach_and_log_err(cx);
});
}
}),
Some(MentionLink::Fetch(url)) => cx.open_url(&url),
Some(MentionLink::Rule(prompt_id)) => window.dispatch_action(
Box::new(OpenRulesLibrary {
@ -743,6 +753,7 @@ impl ActiveThread {
pub fn new(
thread: Entity<Thread>,
thread_store: Entity<ThreadStore>,
text_thread_store: Entity<TextThreadStore>,
context_store: Entity<ContextStore>,
language_registry: Arc<LanguageRegistry>,
workspace: WeakEntity<Workspace>,
@ -765,6 +776,7 @@ impl ActiveThread {
let mut this = Self {
language_registry,
thread_store,
text_thread_store,
context_store,
thread: thread.clone(),
workspace,
@ -844,6 +856,14 @@ impl ActiveThread {
.map(|(id, state)| (*id, state.last_estimated_token_count.unwrap_or(0)))
}
pub fn thread_store(&self) -> &Entity<ThreadStore> {
&self.thread_store
}
pub fn text_thread_store(&self) -> &Entity<TextThreadStore> {
&self.text_thread_store
}
fn push_message(
&mut self,
id: &MessageId,
@ -1264,6 +1284,7 @@ impl ActiveThread {
self.workspace.clone(),
self.context_store.downgrade(),
self.thread_store.downgrade(),
self.text_thread_store.downgrade(),
window,
cx,
);
@ -1285,6 +1306,7 @@ impl ActiveThread {
self.context_store.clone(),
self.workspace.clone(),
Some(self.thread_store.downgrade()),
Some(self.text_thread_store.downgrade()),
context_picker_menu_handle.clone(),
SuggestContextKind::File,
window,
@ -3439,14 +3461,21 @@ pub(crate) fn open_context(
AgentContextHandle::Thread(thread_context) => workspace.update(cx, |workspace, cx| {
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
panel.update(cx, |panel, cx| {
let thread_id = thread_context.thread.read(cx).id().clone();
panel
.open_thread_by_id(&thread_id, window, cx)
.detach_and_log_err(cx)
panel.open_thread(thread_context.thread.clone(), window, cx);
});
}
}),
AgentContextHandle::TextThread(text_thread_context) => {
workspace.update(cx, |workspace, cx| {
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
panel.update(cx, |panel, cx| {
panel.open_prompt_editor(text_thread_context.context.clone(), window, cx)
});
}
})
}
AgentContextHandle::Rules(rules_context) => window.dispatch_action(
Box::new(OpenRulesLibrary {
prompt_to_select: Some(rules_context.prompt_id.0),
@ -3585,18 +3614,25 @@ mod tests {
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
let thread_store = cx
.update(|_, cx| {
ThreadStore::load(
project.clone(),
cx.new(|_| ToolWorkingSet::default()),
None,
Arc::new(PromptBuilder::new(None).unwrap()),
prompt_builder.clone(),
cx,
)
})
.await
.unwrap();
let text_thread_store = cx
.update(|_, cx| {
TextThreadStore::new(project.clone(), prompt_builder, Default::default(), cx)
})
.await
.unwrap();
let thread = thread_store.update(cx, |store, cx| store.create_thread(cx));
let context_store = cx.new(|_cx| ContextStore::new(project.downgrade(), None));
@ -3612,6 +3648,7 @@ mod tests {
ActiveThread::new(
thread.clone(),
thread_store.clone(),
text_thread_store.clone(),
context_store.clone(),
language_registry.clone(),
workspace.downgrade(),