diff --git a/Cargo.lock b/Cargo.lock index 85dce1d932..750e3e0ea8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,6 +660,7 @@ dependencies = [ "collections", "derive_more", "gpui", + "language", "language_model", "parking_lot", "project", diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index f7668da10f..212ef3496f 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/crates/assistant2/src/active_thread.rs @@ -22,10 +22,13 @@ use ui::Color; use ui::{prelude::*, Disclosure, KeyBinding}; use util::ResultExt as _; +use crate::context_store::{refresh_context_store_text, ContextStore}; + pub struct ActiveThread { language_registry: Arc, thread_store: Entity, thread: Entity, + context_store: Entity, save_thread_task: Option>, messages: Vec, list_state: ListState, @@ -46,6 +49,7 @@ impl ActiveThread { thread: Entity, thread_store: Entity, language_registry: Arc, + context_store: Entity, window: &mut Window, cx: &mut Context, ) -> Self { @@ -58,6 +62,7 @@ impl ActiveThread { language_registry, thread_store, thread: thread.clone(), + context_store, save_thread_task: None, messages: Vec::new(), rendered_messages_by_id: HashMap::default(), @@ -350,11 +355,51 @@ impl ActiveThread { } if self.thread.read(cx).all_tools_finished() { + let pending_refresh_buffers = self.thread.update(cx, |thread, cx| { + thread.action_log().update(cx, |action_log, _cx| { + action_log.take_pending_refresh_buffers() + }) + }); + + let context_update_task = if !pending_refresh_buffers.is_empty() { + let refresh_task = refresh_context_store_text( + self.context_store.clone(), + &pending_refresh_buffers, + cx, + ); + + cx.spawn(|this, mut cx| async move { + let updated_context_ids = refresh_task.await; + + this.update(&mut cx, |this, cx| { + this.context_store.read_with(cx, |context_store, cx| { + context_store + .context() + .iter() + .filter(|context| { + updated_context_ids.contains(&context.id()) + }) + .flat_map(|context| context.snapshot(cx)) + .collect() + }) + }) + }) + } else { + Task::ready(anyhow::Ok(Vec::new())) + }; + let model_registry = LanguageModelRegistry::read_global(cx); if let Some(model) = model_registry.active_model() { - self.thread.update(cx, |thread, cx| { - thread.send_tool_results_to_model(model, cx); - }); + cx.spawn(|this, mut cx| async move { + let updated_context = context_update_task.await?; + + this.update(&mut cx, |this, cx| { + this.thread.update(cx, |thread, cx| { + thread.send_tool_results_to_model(model, updated_context, cx); + }); + }) + }) + .detach(); } } } diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 486931a9c3..cb73bfe09c 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -155,10 +155,14 @@ impl AssistantPanel { let workspace = workspace.weak_handle(); let weak_self = cx.entity().downgrade(); + let message_editor_context_store = + cx.new(|_cx| crate::context_store::ContextStore::new(workspace.clone())); + let message_editor = cx.new(|cx| { MessageEditor::new( fs.clone(), workspace.clone(), + message_editor_context_store.clone(), thread_store.downgrade(), thread.clone(), window, @@ -174,6 +178,7 @@ impl AssistantPanel { thread.clone(), thread_store.clone(), language_registry.clone(), + message_editor_context_store.clone(), window, cx, ) @@ -242,11 +247,16 @@ impl AssistantPanel { .update(cx, |this, cx| this.create_thread(cx)); self.active_view = ActiveView::Thread; + + let message_editor_context_store = + cx.new(|_cx| crate::context_store::ContextStore::new(self.workspace.clone())); + self.thread = cx.new(|cx| { ActiveThread::new( thread.clone(), self.thread_store.clone(), self.language_registry.clone(), + message_editor_context_store.clone(), window, cx, ) @@ -255,6 +265,7 @@ impl AssistantPanel { MessageEditor::new( self.fs.clone(), self.workspace.clone(), + message_editor_context_store, self.thread_store.downgrade(), thread, window, @@ -375,11 +386,14 @@ impl AssistantPanel { let thread = open_thread_task.await?; this.update_in(&mut cx, |this, window, cx| { this.active_view = ActiveView::Thread; + let message_editor_context_store = + cx.new(|_cx| crate::context_store::ContextStore::new(this.workspace.clone())); this.thread = cx.new(|cx| { ActiveThread::new( thread.clone(), this.thread_store.clone(), this.language_registry.clone(), + message_editor_context_store.clone(), window, cx, ) @@ -388,6 +402,7 @@ impl AssistantPanel { MessageEditor::new( this.fs.clone(), this.workspace.clone(), + message_editor_context_store, this.thread_store.downgrade(), thread, window, diff --git a/crates/assistant2/src/context_store.rs b/crates/assistant2/src/context_store.rs index 5922f87ca4..f060bb0a40 100644 --- a/crates/assistant2/src/context_store.rs +++ b/crates/assistant2/src/context_store.rs @@ -9,6 +9,7 @@ use language::Buffer; use project::{ProjectPath, Worktree}; use rope::Rope; use text::BufferId; +use util::maybe; use workspace::Workspace; use crate::context::{ @@ -531,35 +532,59 @@ fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec> { pub fn refresh_context_store_text( context_store: Entity, + changed_buffers: &HashSet>, cx: &App, -) -> impl Future { +) -> impl Future> { let mut tasks = Vec::new(); + for context in &context_store.read(cx).context { - match context { - AssistantContext::File(file_context) => { - let context_store = context_store.clone(); - if let Some(task) = refresh_file_text(context_store, file_context, cx) { - tasks.push(task); + let id = context.id(); + + let task = maybe!({ + match context { + AssistantContext::File(file_context) => { + if changed_buffers.is_empty() + || changed_buffers.contains(&file_context.context_buffer.buffer) + { + let context_store = context_store.clone(); + return refresh_file_text(context_store, file_context, cx); + } } - } - AssistantContext::Directory(directory_context) => { - let context_store = context_store.clone(); - if let Some(task) = refresh_directory_text(context_store, directory_context, cx) { - tasks.push(task); + AssistantContext::Directory(directory_context) => { + let should_refresh = changed_buffers.is_empty() + || changed_buffers.iter().any(|buffer| { + let buffer = buffer.read(cx); + + buffer_path_log_err(&buffer) + .map_or(false, |path| path.starts_with(&directory_context.path)) + }); + + if should_refresh { + let context_store = context_store.clone(); + return refresh_directory_text(context_store, directory_context, cx); + } } + AssistantContext::Thread(thread_context) => { + if changed_buffers.is_empty() { + let context_store = context_store.clone(); + return Some(refresh_thread_text(context_store, thread_context, cx)); + } + } + // Intentionally omit refreshing fetched URLs as it doesn't seem all that useful, + // and doing the caching properly could be tricky (unless it's already handled by + // the HttpClient?). + AssistantContext::FetchedUrl(_) => {} } - AssistantContext::Thread(thread_context) => { - let context_store = context_store.clone(); - tasks.push(refresh_thread_text(context_store, thread_context, cx)); - } - // Intentionally omit refreshing fetched URLs as it doesn't seem all that useful, - // and doing the caching properly could be tricky (unless it's already handled by - // the HttpClient?). - AssistantContext::FetchedUrl(_) => {} + + None + }); + + if let Some(task) = task { + tasks.push(task.map(move |_| id)); } } - future::join_all(tasks).map(|_| ()) + future::join_all(tasks) } fn refresh_file_text( diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 26b509fd3e..52e9b56ed2 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use collections::HashSet; use editor::actions::MoveUp; use editor::{Editor, EditorElement, EditorEvent, EditorStyle}; use file_icons::FileIcons; @@ -51,13 +52,13 @@ impl MessageEditor { pub fn new( fs: Arc, workspace: WeakEntity, + context_store: Entity, thread_store: WeakEntity, thread: Entity, window: &mut Window, cx: &mut Context, ) -> Self { let tools = thread.read(cx).tools().clone(); - let context_store = cx.new(|_cx| ContextStore::new(workspace.clone())); let context_picker_menu_handle = PopoverMenuHandle::default(); let inline_context_picker_menu_handle = PopoverMenuHandle::default(); let model_selector_menu_handle = PopoverMenuHandle::default(); @@ -200,7 +201,8 @@ impl MessageEditor { text }); - let refresh_task = refresh_context_store_text(self.context_store.clone(), cx); + let refresh_task = + refresh_context_store_text(self.context_store.clone(), &HashSet::default(), cx); let thread = self.thread.clone(); let context_store = self.context_store.clone(); diff --git a/crates/assistant2/src/thread.rs b/crates/assistant2/src/thread.rs index 871795a6d5..9c744ab123 100644 --- a/crates/assistant2/src/thread.rs +++ b/crates/assistant2/src/thread.rs @@ -2,7 +2,7 @@ use std::io::Write; use std::sync::Arc; use anyhow::{Context as _, Result}; -use assistant_tool::ToolWorkingSet; +use assistant_tool::{ActionLog, ToolWorkingSet}; use chrono::{DateTime, Utc}; use collections::{BTreeMap, HashMap, HashSet}; use futures::future::Shared; @@ -104,6 +104,7 @@ pub struct Thread { prompt_builder: Arc, tools: Arc, tool_use: ToolUseState, + action_log: Entity, scripting_session: Entity, scripting_tool_use: ToolUseState, initial_project_snapshot: Shared>>>, @@ -134,6 +135,7 @@ impl Thread { tool_use: ToolUseState::new(), scripting_session: cx.new(|cx| ScriptingSession::new(project.clone(), cx)), scripting_tool_use: ToolUseState::new(), + action_log: cx.new(|_| ActionLog::new()), initial_project_snapshot: { let project_snapshot = Self::project_snapshot(project, cx); cx.foreground_executor() @@ -191,6 +193,7 @@ impl Thread { prompt_builder, tools, tool_use, + action_log: cx.new(|_| ActionLog::new()), scripting_session, scripting_tool_use, initial_project_snapshot: Task::ready(serialized.initial_project_snapshot).shared(), @@ -750,7 +753,13 @@ impl Thread { 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, &request.messages, self.project.clone(), cx); + let task = tool.run( + tool_use.input, + &request.messages, + self.project.clone(), + self.action_log.clone(), + cx, + ); self.insert_tool_output(tool_use.id.clone(), task, cx); } @@ -857,8 +866,15 @@ impl Thread { pub fn send_tool_results_to_model( &mut self, model: Arc, + updated_context: Vec, cx: &mut Context, ) { + self.context.extend( + updated_context + .into_iter() + .map(|context| (context.id, 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 @@ -1057,6 +1073,10 @@ impl Thread { Ok(String::from_utf8_lossy(&markdown).to_string()) } + pub fn action_log(&self) -> &Entity { + &self.action_log + } + pub fn cumulative_token_usage(&self) -> TokenUsage { self.cumulative_token_usage.clone() } diff --git a/crates/assistant2/src/tool_use.rs b/crates/assistant2/src/tool_use.rs index 01b0379071..34821d45f9 100644 --- a/crates/assistant2/src/tool_use.rs +++ b/crates/assistant2/src/tool_use.rs @@ -226,12 +226,12 @@ impl ToolUseState { output: Result, ) -> Option { match output { - Ok(output) => { + Ok(tool_result) => { self.tool_results.insert( tool_use_id.clone(), LanguageModelToolResult { tool_use_id: tool_use_id.clone(), - content: output.into(), + content: tool_result.into(), is_error: false, }, ); diff --git a/crates/assistant_tool/Cargo.toml b/crates/assistant_tool/Cargo.toml index f30c6d3134..70022fc02c 100644 --- a/crates/assistant_tool/Cargo.toml +++ b/crates/assistant_tool/Cargo.toml @@ -15,8 +15,9 @@ path = "src/assistant_tool.rs" anyhow.workspace = true collections.workspace = true derive_more.workspace = true -language_model.workspace = true gpui.workspace = true +language.workspace = true +language_model.workspace = true parking_lot.workspace = true project.workspace = true serde.workspace = true diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index 5002866287..b466931d89 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -4,7 +4,10 @@ mod tool_working_set; use std::sync::Arc; use anyhow::Result; +use collections::HashSet; +use gpui::Context; use gpui::{App, Entity, SharedString, Task}; +use language::Buffer; use language_model::LanguageModelRequestMessage; use project::Project; @@ -47,6 +50,39 @@ pub trait Tool: 'static + Send + Sync { input: serde_json::Value, messages: &[LanguageModelRequestMessage], project: Entity, + action_log: Entity, cx: &mut App, ) -> Task>; } + +/// Tracks actions performed by tools in a thread +#[derive(Debug)] +pub struct ActionLog { + changed_buffers: HashSet>, + pending_refresh: HashSet>, +} + +impl ActionLog { + /// Creates a new, empty action log. + pub fn new() -> Self { + Self { + changed_buffers: HashSet::default(), + pending_refresh: HashSet::default(), + } + } + + /// Registers buffers that have changed and need refreshing. + pub fn notify_buffers_changed( + &mut self, + buffers: HashSet>, + _cx: &mut Context, + ) { + self.changed_buffers.extend(buffers.clone()); + self.pending_refresh.extend(buffers); + } + + /// Takes and returns the set of buffers pending refresh, clearing internal state. + pub fn take_pending_refresh_buffers(&mut self) -> HashSet> { + std::mem::take(&mut self.pending_refresh) + } +} diff --git a/crates/assistant_tools/src/bash_tool.rs b/crates/assistant_tools/src/bash_tool.rs index 147c5ecc23..5f6d957508 100644 --- a/crates/assistant_tools/src/bash_tool.rs +++ b/crates/assistant_tools/src/bash_tool.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Context as _, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -37,6 +37,7 @@ impl Tool for BashTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let input: BashToolInput = match serde_json::from_value(input) { diff --git a/crates/assistant_tools/src/delete_path_tool.rs b/crates/assistant_tools/src/delete_path_tool.rs index 6a5b3a7ad5..d613cbed12 100644 --- a/crates/assistant_tools/src/delete_path_tool.rs +++ b/crates/assistant_tools/src/delete_path_tool.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -45,6 +45,7 @@ impl Tool for DeletePathTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let glob = match serde_json::from_value::(input) { diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index 5a86b7d5d3..e9d36cc016 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/crates/assistant_tools/src/diagnostics_tool.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language::{DiagnosticSeverity, OffsetRangeExt}; use language_model::LanguageModelRequestMessage; @@ -51,6 +51,7 @@ impl Tool for DiagnosticsTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let input = match serde_json::from_value::(input) { diff --git a/crates/assistant_tools/src/edit_files_tool.rs b/crates/assistant_tools/src/edit_files_tool.rs index 5ef7e7d77a..5534591755 100644 --- a/crates/assistant_tools/src/edit_files_tool.rs +++ b/crates/assistant_tools/src/edit_files_tool.rs @@ -2,13 +2,13 @@ mod edit_action; pub mod log; use anyhow::{anyhow, Context, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use collections::HashSet; use edit_action::{EditAction, EditActionParser}; use futures::StreamExt; use gpui::{App, AsyncApp, Entity, Task}; use language_model::{ - LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, Role, + LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, MessageContent, Role, }; use log::{EditToolLog, EditToolRequestId}; use project::{search::SearchQuery, Project}; @@ -80,6 +80,7 @@ impl Tool for EditFilesTool { input: serde_json::Value, messages: &[LanguageModelRequestMessage], project: Entity, + action_log: Entity, cx: &mut App, ) -> Task> { let input = match serde_json::from_value::(input) { @@ -93,8 +94,14 @@ impl Tool for EditFilesTool { log.new_request(input.edit_instructions.clone(), cx) }); - let task = - EditToolRequest::new(input, messages, project, Some((log.clone(), req_id)), cx); + let task = EditToolRequest::new( + input, + messages, + project, + action_log, + Some((log.clone(), req_id)), + cx, + ); cx.spawn(|mut cx| async move { let result = task.await; @@ -113,7 +120,7 @@ impl Tool for EditFilesTool { }) } - None => EditToolRequest::new(input, messages, project, None, cx), + None => EditToolRequest::new(input, messages, project, action_log, None, cx), } } } @@ -123,7 +130,8 @@ struct EditToolRequest { changed_buffers: HashSet>, bad_searches: Vec, project: Entity, - log: Option<(Entity, EditToolRequestId)>, + action_log: Entity, + tool_log: Option<(Entity, EditToolRequestId)>, } #[derive(Debug)] @@ -143,7 +151,8 @@ impl EditToolRequest { input: EditFilesToolInput, messages: &[LanguageModelRequestMessage], project: Entity, - log: Option<(Entity, EditToolRequestId)>, + action_log: Entity, + tool_log: Option<(Entity, EditToolRequestId)>, cx: &mut App, ) -> Task> { let model_registry = LanguageModelRegistry::read_global(cx); @@ -152,12 +161,23 @@ impl EditToolRequest { }; let mut messages = messages.to_vec(); - if let Some(last_message) = messages.last_mut() { - // Strip out tool use from the last message because we're in the middle of executing a tool call. - last_message - .content - .retain(|content| !matches!(content, language_model::MessageContent::ToolUse(_))) + // Remove the last tool use (this run) to prevent an invalid request + 'outer: for message in messages.iter_mut().rev() { + for (index, content) in message.content.iter().enumerate().rev() { + match content { + MessageContent::ToolUse(_) => { + message.content.remove(index); + break 'outer; + } + MessageContent::ToolResult(_) => { + // If we find any tool results before a tool use, the request is already valid + break 'outer; + } + MessageContent::Text(_) | MessageContent::Image(_) => {} + } + } } + messages.push(LanguageModelRequestMessage { role: Role::User, content: vec![ @@ -182,8 +202,9 @@ impl EditToolRequest { parser: EditActionParser::new(), changed_buffers: HashSet::default(), bad_searches: Vec::new(), + action_log, project, - log, + tool_log, }; while let Some(chunk) = chunks.stream.next().await { @@ -197,7 +218,7 @@ impl EditToolRequest { async fn process_response_chunk(&mut self, chunk: &str, cx: &mut AsyncApp) -> Result<()> { let new_actions = self.parser.parse_chunk(chunk); - if let Some((ref log, req_id)) = self.log { + if let Some((ref log, req_id)) = self.tool_log { log.update(cx, |log, cx| { log.push_editor_response_chunk(req_id, chunk, &new_actions, cx) }) @@ -310,7 +331,7 @@ impl EditToolRequest { }; // Save each buffer once at the end - for buffer in self.changed_buffers { + for buffer in &self.changed_buffers { let (path, save_task) = self.project.update(cx, |project, cx| { let path = buffer .read(cx) @@ -329,10 +350,17 @@ impl EditToolRequest { } } + self.action_log + .update(cx, |log, cx| { + log.notify_buffers_changed(self.changed_buffers, cx) + }) + .log_err(); + let errors = self.parser.errors(); if errors.is_empty() && self.bad_searches.is_empty() { - Ok(answer.trim_end().to_string()) + let answer = answer.trim_end().to_string(); + Ok(answer) } else { if !self.bad_searches.is_empty() { writeln!( @@ -369,7 +397,7 @@ impl EditToolRequest { but errors are part of the conversation so you don't need to repeat them." )?; - Err(anyhow!(answer)) + Err(anyhow!(answer.trim_end().to_string())) } } } diff --git a/crates/assistant_tools/src/list_directory_tool.rs b/crates/assistant_tools/src/list_directory_tool.rs index 3737319f26..b43010b6ef 100644 --- a/crates/assistant_tools/src/list_directory_tool.rs +++ b/crates/assistant_tools/src/list_directory_tool.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -55,6 +55,7 @@ impl Tool for ListDirectoryTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let input = match serde_json::from_value::(input) { diff --git a/crates/assistant_tools/src/now_tool.rs b/crates/assistant_tools/src/now_tool.rs index 80332a184e..e10bddb669 100644 --- a/crates/assistant_tools/src/now_tool.rs +++ b/crates/assistant_tools/src/now_tool.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use chrono::{Local, Utc}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; @@ -45,6 +45,7 @@ impl Tool for NowTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], _project: Entity, + _action_log: Entity, _cx: &mut App, ) -> Task> { let input: NowToolInput = match serde_json::from_value(input) { diff --git a/crates/assistant_tools/src/path_search_tool.rs b/crates/assistant_tools/src/path_search_tool.rs index 00ac703216..dfa7ab0f73 100644 --- a/crates/assistant_tools/src/path_search_tool.rs +++ b/crates/assistant_tools/src/path_search_tool.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -45,6 +45,7 @@ impl Tool for PathSearchTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let glob = match serde_json::from_value::(input) { diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs index 2190c721e9..d4c69df8e5 100644 --- a/crates/assistant_tools/src/read_file_tool.rs +++ b/crates/assistant_tools/src/read_file_tool.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::sync::Arc; use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -49,6 +49,7 @@ impl Tool for ReadFileTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { let input = match serde_json::from_value::(input) { diff --git a/crates/assistant_tools/src/regex_search.rs b/crates/assistant_tools/src/regex_search.rs index 9cdf269594..a6eca996a7 100644 --- a/crates/assistant_tools/src/regex_search.rs +++ b/crates/assistant_tools/src/regex_search.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use assistant_tool::Tool; +use assistant_tool::{ActionLog, Tool}; use futures::StreamExt; use gpui::{App, Entity, Task}; use language::OffsetRangeExt; @@ -38,6 +38,7 @@ impl Tool for RegexSearchTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { const CONTEXT_LINES: u32 = 2; @@ -110,7 +111,7 @@ impl Tool for RegexSearchTool { } if output.is_empty() { - Ok("No matches found".into()) + Ok("No matches found".to_string()) } else { Ok(output) } diff --git a/crates/context_server/src/context_server_tool.rs b/crates/context_server/src/context_server_tool.rs index 899db58c7d..315bb6bce3 100644 --- a/crates/context_server/src/context_server_tool.rs +++ b/crates/context_server/src/context_server_tool.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use anyhow::{anyhow, bail, Result}; -use assistant_tool::{Tool, ToolSource}; +use assistant_tool::{ActionLog, Tool, ToolSource}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; @@ -61,6 +61,7 @@ impl Tool for ContextServerTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], _project: Entity, + _action_log: Entity, cx: &mut App, ) -> Task> { if let Some(server) = self.server_manager.read(cx).get_server(&self.server_id) {