diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index c0ff2596ae..707daf03b1 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -2198,6 +2198,47 @@ impl ContextEditor { } } } + ContextEvent::ToolFinished { + tool_use_id, + output_range, + } => { + self.editor.update(cx, |editor, cx| { + let buffer = editor.buffer().read(cx).snapshot(cx); + let (excerpt_id, _buffer_id, _) = buffer.as_singleton().unwrap(); + let excerpt_id = *excerpt_id; + + let placeholder = FoldPlaceholder { + render: render_fold_icon_button( + cx.view().downgrade(), + IconName::PocketKnife, + format!("Tool Result: {tool_use_id}").into(), + ), + constrain_width: false, + merge_adjacent: false, + }; + let render_trailer = + move |_row, _unfold, _cx: &mut WindowContext| Empty.into_any(); + + let start = buffer + .anchor_in_excerpt(excerpt_id, output_range.start) + .unwrap(); + let end = buffer + .anchor_in_excerpt(excerpt_id, output_range.end) + .unwrap(); + + let buffer_row = MultiBufferRow(start.to_point(&buffer).row); + + let crease = Crease::new( + start..end, + placeholder, + fold_toggle("tool-use"), + render_trailer, + ); + + editor.insert_creases([crease], cx); + editor.fold_at(&FoldAt { buffer_row }, cx); + }); + } ContextEvent::Operation(_) => {} ContextEvent::ShowAssistError(error_message) => { self.error_message = Some(error_message.clone()); diff --git a/crates/assistant/src/context.rs b/crates/assistant/src/context.rs index b4842ccc8f..98146485bf 100644 --- a/crates/assistant/src/context.rs +++ b/crates/assistant/src/context.rs @@ -307,6 +307,10 @@ pub enum ContextEvent { expand_result: bool, }, UsePendingTools, + ToolFinished { + tool_use_id: Arc, + output_range: Range, + }, Operation(ContextOperation), } @@ -1923,28 +1927,43 @@ impl Context { pub fn insert_tool_output( &mut self, - tool_id: Arc, + tool_use_id: Arc, output: Task>, cx: &mut ModelContext, ) { let insert_output_task = cx.spawn(|this, mut cx| { - let tool_id = tool_id.clone(); + let tool_use_id = tool_use_id.clone(); async move { let output = output.await; this.update(&mut cx, |this, cx| match output { Ok(mut output) => { - if !output.ends_with('\n') { - output.push('\n'); + const NEWLINE: char = '\n'; + + if !output.ends_with(NEWLINE) { + output.push(NEWLINE); } - this.buffer.update(cx, |buffer, cx| { - let buffer_end = buffer.len().to_offset(buffer); + let anchor_range = this.buffer.update(cx, |buffer, cx| { + let insert_start = buffer.len().to_offset(buffer); + let insert_end = insert_start; - buffer.edit([(buffer_end..buffer_end, output)], None, cx); + let start = insert_start; + let end = start + output.len() - NEWLINE.len_utf8(); + + buffer.edit([(insert_start..insert_end, output)], None, cx); + + let output_range = buffer.anchor_after(start)..buffer.anchor_after(end); + + output_range + }); + + cx.emit(ContextEvent::ToolFinished { + tool_use_id, + output_range: anchor_range, }); } Err(err) => { - if let Some(tool_use) = this.pending_tool_uses_by_id.get_mut(&tool_id) { + if let Some(tool_use) = this.pending_tool_uses_by_id.get_mut(&tool_use_id) { tool_use.status = PendingToolUseStatus::Error(err.to_string()); } } @@ -1953,7 +1972,7 @@ impl Context { } }); - if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_id) { + if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) { tool_use.status = PendingToolUseStatus::Running { _task: insert_output_task.shared(), };