agent: Return an error to the model when trying to use a tool that is disabled (#27928)

Marshall Bowers created

This PR makes it so we return an error to the model if it tries to use a
tool that is not currently enabled:

<img width="628" alt="Screenshot 2025-04-02 at 11 10 55 AM"
src="https://github.com/user-attachments/assets/e4bdf01c-f0ea-4c9c-805a-11868bd9c771"
/>

This allows the model to adapt based on that:

<img width="637" alt="Screenshot 2025-04-02 at 11 08 38 AM"
src="https://github.com/user-attachments/assets/41016b47-933c-4dcb-b791-847be0548c8a"
/>

Release Notes:

- N/A

Change summary

crates/agent/src/thread.rs | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

Detailed changes

crates/agent/src/thread.rs 🔗

@@ -3,7 +3,7 @@ use std::io::Write;
 use std::ops::Range;
 use std::sync::Arc;
 
-use anyhow::{Context as _, Result};
+use anyhow::{Context as _, Result, anyhow};
 use assistant_settings::AssistantSettings;
 use assistant_tool::{ActionLog, Tool, ToolWorkingSet};
 use chrono::{DateTime, Utc};
@@ -1403,13 +1403,18 @@ impl Thread {
         cx: &mut Context<Thread>,
     ) -> Task<()> {
         let tool_name: Arc<str> = tool.name().into();
-        let run_tool = tool.run(
-            input,
-            messages,
-            self.project.clone(),
-            self.action_log.clone(),
-            cx,
-        );
+
+        let run_tool = if self.tools.is_disabled(&tool.source(), &tool_name) {
+            Task::ready(Err(anyhow!("tool is disabled: {tool_name}")))
+        } else {
+            tool.run(
+                input,
+                messages,
+                self.project.clone(),
+                self.action_log.clone(),
+                cx,
+            )
+        };
 
         cx.spawn({
             async move |thread: WeakEntity<Thread>, cx| {