From 37540d1ff7c0394b4b2b721c86c7c1615e7418d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Dur=C3=A1n=20Carvajal?= Date: Tue, 28 Oct 2025 10:56:39 -0600 Subject: [PATCH] agent: Only include tool guidance in system prompt when profile has tools enabled (#40413) Was previously sending all of the tools to the LLM on the first message of a conversation regardless of the selected agent profile. This added extra context, and tended to create scenarios where the LLM would attempt to use the tool and it would fail since it was not available. To reproduce, create a new conversation where you ask the Minimal mode which tools it has access to, or try to write to a file. Release Notes: - Fixed an issue in the agent where all tools would be presented as available even when using the `Minimal` profile --------- Co-authored-by: Bennet Bo Fenner --- crates/agent/src/tests/mod.rs | 36 +++++++++++++++++++++++++++++++++++ crates/agent/src/thread.rs | 18 ++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/crates/agent/src/tests/mod.rs b/crates/agent/src/tests/mod.rs index ddddbfc527..20fc40f242 100644 --- a/crates/agent/src/tests/mod.rs +++ b/crates/agent/src/tests/mod.rs @@ -160,6 +160,42 @@ async fn test_system_prompt(cx: &mut TestAppContext) { ); } +#[gpui::test] +async fn test_system_prompt_without_tools(cx: &mut TestAppContext) { + let ThreadTest { model, thread, .. } = setup(cx, TestModel::Fake).await; + let fake_model = model.as_fake(); + + thread + .update(cx, |thread, cx| { + thread.send(UserMessageId::new(), ["abc"], cx) + }) + .unwrap(); + cx.run_until_parked(); + let mut pending_completions = fake_model.pending_completions(); + assert_eq!( + pending_completions.len(), + 1, + "unexpected pending completions: {:?}", + pending_completions + ); + + let pending_completion = pending_completions.pop().unwrap(); + assert_eq!(pending_completion.messages[0].role, Role::System); + + let system_message = &pending_completion.messages[0]; + let system_prompt = system_message.content[0].to_str().unwrap(); + assert!( + !system_prompt.contains("## Tool Use"), + "unexpected system message: {:?}", + system_message + ); + assert!( + !system_prompt.contains("## Fixing Diagnostics"), + "unexpected system message: {:?}", + system_message + ); +} + #[gpui::test] async fn test_prompt_caching(cx: &mut TestAppContext) { let ThreadTest { model, thread, .. } = setup(cx, TestModel::Fake).await; diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index 4016f3a5f5..64e512690b 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -1816,9 +1816,15 @@ impl Thread { log::debug!("Completion intent: {:?}", completion_intent); log::debug!("Completion mode: {:?}", self.completion_mode); - let messages = self.build_request_messages(cx); + let available_tools: Vec<_> = self + .running_turn + .as_ref() + .map(|turn| turn.tools.keys().cloned().collect()) + .unwrap_or_default(); + + log::debug!("Request includes {} tools", available_tools.len()); + let messages = self.build_request_messages(available_tools, cx); log::debug!("Request will include {} messages", messages.len()); - log::debug!("Request includes {} tools", tools.len()); let request = LanguageModelRequest { thread_id: Some(self.id.to_string()), @@ -1909,7 +1915,11 @@ impl Thread { self.running_turn.as_ref()?.tools.get(name).cloned() } - fn build_request_messages(&self, cx: &App) -> Vec { + fn build_request_messages( + &self, + available_tools: Vec, + cx: &App, + ) -> Vec { log::trace!( "Building request messages from {} thread messages", self.messages.len() @@ -1917,7 +1927,7 @@ impl Thread { let system_prompt = SystemPromptTemplate { project: self.project_context.read(cx), - available_tools: self.tools.keys().cloned().collect(), + available_tools, } .render(&self.templates) .context("failed to build system prompt")