diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index c3181b422c0e2bee0d54a98caefb0e0f5999d0fc..9a6239744b457bdc64698318838e092c05ba2b0f 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/crates/assistant2/src/active_thread.rs @@ -1,17 +1,15 @@ use std::sync::Arc; -use assistant_tool::ToolWorkingSet; use collections::HashMap; use editor::{Editor, MultiBuffer}; use gpui::{ list, AbsoluteLength, AnyElement, App, ClickEvent, DefiniteLength, EdgesRefinement, Empty, Entity, Focusable, Length, ListAlignment, ListOffset, ListState, StyleRefinement, Subscription, - Task, TextStyleRefinement, UnderlineStyle, WeakEntity, + Task, TextStyleRefinement, UnderlineStyle, }; use language::{Buffer, LanguageRegistry}; use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role}; use markdown::{Markdown, MarkdownStyle}; -use project::Project; use settings::Settings as _; use theme::ThemeSettings; use ui::{prelude::*, Disclosure, KeyBinding}; @@ -23,9 +21,7 @@ use crate::tool_use::{ToolUse, ToolUseStatus}; use crate::ui::ContextPill; pub struct ActiveThread { - project: WeakEntity, language_registry: Arc, - tools: Arc, thread_store: Entity, thread: Entity, save_thread_task: Option>, @@ -46,9 +42,7 @@ impl ActiveThread { pub fn new( thread: Entity, thread_store: Entity, - project: WeakEntity, language_registry: Arc, - tools: Arc, window: &mut Window, cx: &mut Context, ) -> Self { @@ -58,9 +52,7 @@ impl ActiveThread { ]; let mut this = Self { - project, language_registry, - tools, thread_store, thread: thread.clone(), save_thread_task: None, @@ -300,24 +292,9 @@ impl ActiveThread { cx.notify(); } ThreadEvent::UsePendingTools => { - let pending_tool_uses = self - .thread - .read(cx) - .pending_tool_uses() - .into_iter() - .filter(|tool_use| tool_use.status.is_idle()) - .cloned() - .collect::>(); - - for tool_use in pending_tool_uses { - if let Some(tool) = self.tools.tool(&tool_use.name, cx) { - let task = tool.run(tool_use.input, self.project.clone(), cx); - - self.thread.update(cx, |thread, cx| { - thread.insert_tool_output(tool_use.id.clone(), task, cx); - }); - } - } + self.thread.update(cx, |thread, cx| { + thread.use_pending_tools(cx); + }); } ThreadEvent::ToolFinished { .. } => { let all_tools_finished = self @@ -330,16 +307,7 @@ impl ActiveThread { let model_registry = LanguageModelRegistry::read_global(cx); if let Some(model) = model_registry.active_model() { self.thread.update(cx, |thread, cx| { - // Insert a user message to contain the tool results. - thread.insert_user_message( - // TODO: Sending up a user message without any content results in the model sending back - // responses that also don't have any content. We currently don't handle this case well, - // so for now we provide some text to keep the model on track. - "Here are the tool results.", - Vec::new(), - cx, - ); - thread.send_to_model(model, RequestKind::Chat, true, cx); + thread.send_tool_results_to_model(model, cx); }); } } diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index ef29610a9b8e566118da5cc3f5e7d376cc5c146d..301466ae5f8363d5bdccb111772ce1a8d44c1b28 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -92,7 +92,6 @@ pub struct AssistantPanel { context_editor: Option>, configuration: Option>, configuration_subscription: Option, - tools: Arc, local_timezone: UtcOffset, active_view: ActiveView, history_store: Entity, @@ -133,7 +132,7 @@ impl AssistantPanel { log::info!("[assistant2-debug] finished initializing ContextStore"); workspace.update_in(&mut cx, |workspace, window, cx| { - cx.new(|cx| Self::new(workspace, thread_store, context_store, tools, window, cx)) + cx.new(|cx| Self::new(workspace, thread_store, context_store, window, cx)) }) }) } @@ -142,7 +141,6 @@ impl AssistantPanel { workspace: &Workspace, thread_store: Entity, context_store: Entity, - tools: Arc, window: &mut Window, cx: &mut Context, ) -> Self { @@ -179,9 +177,7 @@ impl AssistantPanel { ActiveThread::new( thread.clone(), thread_store.clone(), - project.downgrade(), language_registry, - tools.clone(), window, cx, ) @@ -191,7 +187,6 @@ impl AssistantPanel { context_editor: None, configuration: None, configuration_subscription: None, - tools, local_timezone: UtcOffset::from_whole_seconds( chrono::Local::now().offset().local_minus_utc(), ) @@ -246,9 +241,7 @@ impl AssistantPanel { ActiveThread::new( thread.clone(), self.thread_store.clone(), - self.project.downgrade(), self.language_registry.clone(), - self.tools.clone(), window, cx, ) @@ -381,9 +374,7 @@ impl AssistantPanel { ActiveThread::new( thread.clone(), this.thread_store.clone(), - this.project.downgrade(), this.language_registry.clone(), - this.tools.clone(), window, cx, ) diff --git a/crates/assistant2/src/thread.rs b/crates/assistant2/src/thread.rs index 368902fadaa4d668b57dc679ed0d20d05a218348..df9b1c370cf2340d74322a73b1d096a00fc79840 100644 --- a/crates/assistant2/src/thread.rs +++ b/crates/assistant2/src/thread.rs @@ -5,13 +5,14 @@ use assistant_tool::ToolWorkingSet; use chrono::{DateTime, Utc}; use collections::{BTreeMap, HashMap, HashSet}; use futures::StreamExt as _; -use gpui::{App, Context, EventEmitter, SharedString, Task}; +use gpui::{App, Context, Entity, EventEmitter, SharedString, Task, WeakEntity}; use language_model::{ LanguageModel, LanguageModelCompletionEvent, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult, LanguageModelToolUseId, MaxMonthlySpendReachedError, MessageContent, PaymentRequiredError, Role, StopReason, }; +use project::Project; use serde::{Deserialize, Serialize}; use util::{post_inc, TryFutureExt as _}; use uuid::Uuid; @@ -71,12 +72,17 @@ pub struct Thread { context_by_message: HashMap>, completion_count: usize, pending_completions: Vec, + project: WeakEntity, tools: Arc, tool_use: ToolUseState, } impl Thread { - pub fn new(tools: Arc, _cx: &mut Context) -> Self { + pub fn new( + project: Entity, + tools: Arc, + _cx: &mut Context, + ) -> Self { Self { id: ThreadId::new(), updated_at: Utc::now(), @@ -88,6 +94,7 @@ impl Thread { context_by_message: HashMap::default(), completion_count: 0, pending_completions: Vec::new(), + project: project.downgrade(), tools, tool_use: ToolUseState::new(), } @@ -96,6 +103,7 @@ impl Thread { pub fn from_saved( id: ThreadId, saved: SavedThread, + project: Entity, tools: Arc, _cx: &mut Context, ) -> Self { @@ -127,6 +135,7 @@ impl Thread { context_by_message: HashMap::default(), completion_count: 0, pending_completions: Vec::new(), + project: project.downgrade(), tools, tool_use, } @@ -550,6 +559,23 @@ impl Thread { }); } + pub fn use_pending_tools(&mut self, cx: &mut Context) { + let pending_tool_uses = self + .pending_tool_uses() + .into_iter() + .filter(|tool_use| tool_use.status.is_idle()) + .cloned() + .collect::>(); + + for tool_use in pending_tool_uses { + if let Some(tool) = self.tools.tool(&tool_use.name, cx) { + let task = tool.run(tool_use.input, self.project.clone(), cx); + + self.insert_tool_output(tool_use.id.clone(), task, cx); + } + } + } + pub fn insert_tool_output( &mut self, tool_use_id: LanguageModelToolUseId, @@ -576,6 +602,23 @@ impl Thread { .run_pending_tool(tool_use_id, insert_output_task); } + pub fn send_tool_results_to_model( + &mut self, + model: Arc, + cx: &mut Context, + ) { + // Insert a user message to contain the tool results. + self.insert_user_message( + // TODO: Sending up a user message without any content results in the model sending back + // responses that also don't have any content. We currently don't handle this case well, + // so for now we provide some text to keep the model on track. + "Here are the tool results.", + Vec::new(), + cx, + ); + self.send_to_model(model, RequestKind::Chat, true, cx); + } + /// Cancels the last pending completion, if there are any pending. /// /// Returns whether a completion was canceled. diff --git a/crates/assistant2/src/thread_store.rs b/crates/assistant2/src/thread_store.rs index f6143186828ccd47160c971611f06540075e1346..4d9dc8244945ac1e11ce0e1a620612d905831bc4 100644 --- a/crates/assistant2/src/thread_store.rs +++ b/crates/assistant2/src/thread_store.rs @@ -26,7 +26,6 @@ pub fn init(cx: &mut App) { } pub struct ThreadStore { - #[allow(unused)] project: Entity, tools: Arc, context_server_manager: Entity, @@ -78,7 +77,7 @@ impl ThreadStore { } pub fn create_thread(&mut self, cx: &mut Context) -> Entity { - cx.new(|cx| Thread::new(self.tools.clone(), cx)) + cx.new(|cx| Thread::new(self.project.clone(), self.tools.clone(), cx)) } pub fn open_thread( @@ -96,7 +95,15 @@ impl ThreadStore { .ok_or_else(|| anyhow!("no thread found with ID: {id:?}"))?; this.update(&mut cx, |this, cx| { - cx.new(|cx| Thread::from_saved(id.clone(), thread, this.tools.clone(), cx)) + cx.new(|cx| { + Thread::from_saved( + id.clone(), + thread, + this.project.clone(), + this.tools.clone(), + cx, + ) + }) }) }) }