From 1bf1c7223f5549217170e28eb30c8f9c8a2cd7c5 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 14 Mar 2025 17:07:43 -0300 Subject: [PATCH] assistant edit tool: Fix editing files in context (#26751) When the user attached context in the thread, the editor model request would fail because its tool use wouldn't be removed properly leading to an API error. Also, after an edit, we'd keep the old file snapshot in the context. This would make the model think that the edits didn't apply and make it go in a loop. Release Notes: - N/A --- Cargo.lock | 1 + crates/assistant2/src/active_thread.rs | 51 ++++++++++++++- crates/assistant2/src/assistant_panel.rs | 15 +++++ crates/assistant2/src/context_store.rs | 65 +++++++++++++------ crates/assistant2/src/message_editor.rs | 6 +- crates/assistant2/src/thread.rs | 24 ++++++- crates/assistant2/src/tool_use.rs | 4 +- crates/assistant_tool/Cargo.toml | 3 +- crates/assistant_tool/src/assistant_tool.rs | 36 ++++++++++ crates/assistant_tools/src/bash_tool.rs | 3 +- .../assistant_tools/src/delete_path_tool.rs | 3 +- .../assistant_tools/src/diagnostics_tool.rs | 3 +- crates/assistant_tools/src/edit_files_tool.rs | 62 +++++++++++++----- .../src/list_directory_tool.rs | 3 +- crates/assistant_tools/src/now_tool.rs | 3 +- .../assistant_tools/src/path_search_tool.rs | 3 +- crates/assistant_tools/src/read_file_tool.rs | 3 +- crates/assistant_tools/src/regex_search.rs | 5 +- .../context_server/src/context_server_tool.rs | 3 +- 19 files changed, 239 insertions(+), 57 deletions(-) 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) {