From 130abc8998f5cc3290cb57a88e6ebdb85b982db5 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Wed, 26 Mar 2025 13:42:09 -0300 Subject: [PATCH] assistant2: Encourage diagnostics check (#27510) Release Notes: - N/A --- assets/prompts/assistant_system_prompt.hbs | 2 ++ crates/assistant2/src/thread.rs | 26 ++++++++++++++++--- crates/assistant_tool/src/assistant_tool.rs | 14 ++++++++++ .../assistant_tools/src/diagnostics_tool.rs | 16 +++++++++++- .../src/diagnostics_tool/description.md | 2 ++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/assets/prompts/assistant_system_prompt.hbs b/assets/prompts/assistant_system_prompt.hbs index a377a1ae85..d0a70d5375 100644 --- a/assets/prompts/assistant_system_prompt.hbs +++ b/assets/prompts/assistant_system_prompt.hbs @@ -8,6 +8,8 @@ It will be up to you to decide which of these you are doing based on what the us You should only perform actions that modify the user’s system if explicitly requested by the user: - If the user asks a question about how to accomplish a task, provide guidance or information, and use read-only tools (e.g., search) to assist. You may suggest potential actions, but do not directly modify the user’s system without explicit instruction. - If the user clearly requests that you perform an action, carry out the action directly without explaining why you are doing so. +- The editing actions you perform might produce errors or warnings. At the end of your changes, check whether you introduced any problems, and fix them before providing a summary of the changes you made. +- Do not fix errors unrelated to your changes unless the user explicitly asks you to do so. Be concise and direct in your responses. diff --git a/crates/assistant2/src/thread.rs b/crates/assistant2/src/thread.rs index 0b432def5f..711fa219a3 100644 --- a/crates/assistant2/src/thread.rs +++ b/crates/assistant2/src/thread.rs @@ -873,17 +873,23 @@ impl Thread { request.messages.push(context_message); } - self.attach_stale_files(&mut request.messages, cx); + self.attached_tracked_files_state(&mut request.messages, cx); request } - fn attach_stale_files(&self, messages: &mut Vec, cx: &App) { + fn attached_tracked_files_state( + &self, + messages: &mut Vec, + cx: &App, + ) { const STALE_FILES_HEADER: &str = "These files changed since last read:"; let mut stale_message = String::new(); - for stale_file in self.action_log.read(cx).stale_buffers(cx) { + let action_log = self.action_log.read(cx); + + for stale_file in action_log.stale_buffers(cx) { let Some(file) = stale_file.read(cx).file() else { continue; }; @@ -895,10 +901,22 @@ impl Thread { writeln!(&mut stale_message, "- {}", file.path().display()).ok(); } + let mut content = Vec::with_capacity(2); + if !stale_message.is_empty() { + content.push(stale_message.into()); + } + + if action_log.has_edited_files_since_project_diagnostics_check() { + content.push( + "When you're done making changes, make sure to check project diagnostics and fix all errors AND warnings you introduced!".into(), + ); + } + + if !content.is_empty() { let context_message = LanguageModelRequestMessage { role: Role::User, - content: vec![stale_message.into()], + content, cache: false, }; diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index 906903acbb..25a6106490 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -80,6 +80,8 @@ pub struct ActionLog { stale_buffers_in_context: HashSet>, /// Buffers that we want to notify the model about when they change. tracked_buffers: HashMap, TrackedBuffer>, + /// Has the model edited a file since it last checked diagnostics? + edited_since_project_diagnostics_check: bool, } #[derive(Debug, Default)] @@ -93,6 +95,7 @@ impl ActionLog { Self { stale_buffers_in_context: HashSet::default(), tracked_buffers: HashMap::default(), + edited_since_project_diagnostics_check: false, } } @@ -110,6 +113,12 @@ impl ActionLog { } self.stale_buffers_in_context.extend(buffers); + self.edited_since_project_diagnostics_check = true; + } + + /// Notifies a diagnostics check + pub fn checked_project_diagnostics(&mut self) { + self.edited_since_project_diagnostics_check = false; } /// Iterate over buffers changed since last read or edited by the model @@ -120,6 +129,11 @@ impl ActionLog { .map(|(buffer, _)| buffer) } + /// Returns true if any files have been edited since the last project diagnostics check + pub fn has_edited_files_since_project_diagnostics_check(&self) -> bool { + self.edited_since_project_diagnostics_check + } + /// Takes and returns the set of buffers pending refresh, clearing internal state. pub fn take_stale_buffers_in_context(&mut self) -> HashSet> { std::mem::take(&mut self.stale_buffers_in_context) diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index 6b51ec1586..c7c944dafe 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/crates/assistant_tools/src/diagnostics_tool.rs @@ -25,9 +25,19 @@ pub struct DiagnosticsToolInput { /// /// If you wanna access diagnostics for `dolor.txt` in `ipsum`, you should use the path `ipsum/dolor.txt`. /// + #[serde(deserialize_with = "deserialize_path")] pub path: Option, } +fn deserialize_path<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let opt = Option::::deserialize(deserializer)?; + // The model passes an empty string sometimes + Ok(opt.filter(|s| !s.is_empty())) +} + pub struct DiagnosticsTool; impl Tool for DiagnosticsTool { @@ -71,7 +81,7 @@ impl Tool for DiagnosticsTool { input: serde_json::Value, _messages: &[LanguageModelRequestMessage], project: Entity, - _action_log: Entity, + action_log: Entity, cx: &mut App, ) -> Task> { match serde_json::from_value::(input) @@ -140,6 +150,10 @@ impl Tool for DiagnosticsTool { } } + action_log.update(cx, |action_log, _cx| { + action_log.checked_project_diagnostics(); + }); + if has_diagnostics { Task::ready(Ok(output)) } else { diff --git a/crates/assistant_tools/src/diagnostics_tool/description.md b/crates/assistant_tools/src/diagnostics_tool/description.md index 556daf04fe..4ebf9b0e82 100644 --- a/crates/assistant_tools/src/diagnostics_tool/description.md +++ b/crates/assistant_tools/src/diagnostics_tool/description.md @@ -14,3 +14,5 @@ To get diagnostics for a specific file: To get a project-wide diagnostic summary: {} + +IMPORTANT: When you're done making changes, you **MUST** get the **project** diagnostics (input: `{}`) at the end of your edits so you can fix any problems you might have introduced. **DO NOT** tell the user you're done before doing this!