assistant2: Factor out `Thread::all_tools_finished` method (#26314)

Marshall Bowers created

This PR factors out a new `Thread::all_tools_finished` method to
encapsulate some of the boilerplate in the `ThreadEvent::ToolFinished`
event handler.

This should make this event handler easier to replicate for the eval
use-case.

Release Notes:

- N/A

Change summary

crates/assistant2/src/active_thread.rs | 8 +-------
crates/assistant2/src/thread.rs        | 9 +++++++++
2 files changed, 10 insertions(+), 7 deletions(-)

Detailed changes

crates/assistant2/src/active_thread.rs 🔗

@@ -297,13 +297,7 @@ impl ActiveThread {
                 });
             }
             ThreadEvent::ToolFinished { .. } => {
-                let all_tools_finished = self
-                    .thread
-                    .read(cx)
-                    .pending_tool_uses()
-                    .into_iter()
-                    .all(|tool_use| tool_use.status.is_error());
-                if all_tools_finished {
+                if self.thread.read(cx).all_tools_finished() {
                     let model_registry = LanguageModelRegistry::read_global(cx);
                     if let Some(model) = model_registry.active_model() {
                         self.thread.update(cx, |thread, cx| {

crates/assistant2/src/thread.rs 🔗

@@ -202,6 +202,15 @@ impl Thread {
         self.tool_use.pending_tool_uses()
     }
 
+    /// Returns whether all of the tool uses have finished running.
+    pub fn all_tools_finished(&self) -> bool {
+        // If the only pending tool uses left are the ones with errors, then that means that we've finished running all
+        // of the pending tools.
+        self.pending_tool_uses()
+            .into_iter()
+            .all(|tool_use| tool_use.status.is_error())
+    }
+
     pub fn tool_uses_for_message(&self, id: MessageId) -> Vec<ToolUse> {
         self.tool_use.tool_uses_for_message(id)
     }