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 ddddbfc5279ca23fb95527892e929b23b8cefbf6..20fc40f242831552630f1e15f59917fd80b1ecdb 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 4016f3a5f53da95c0adca80ebfc5808addd55e09..64e512690beeaebd4a343bc5f2df473c795aed3f 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")