Prompt before running some tools (#27284)

Also includes some fixes for how the Lua tool was being generated.

<img width="644" alt="Screenshot 2025-03-21 at 6 26 18 PM"
src="https://github.com/user-attachments/assets/51bd1685-5b3f-4ed3-b11e-6fa8017847d4"
/>


Release Notes:

- N/A

---------

Co-authored-by: Ben <ben@zed.dev>
Co-authored-by: Agus Zubiaga <agus@zed.dev>
Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
This commit is contained in:
Richard Feldman 2025-03-22 00:05:34 -04:00 committed by GitHub
parent 90649fbc89
commit 4c86cda909
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 666 additions and 329 deletions

View file

@ -1,7 +1,7 @@
use std::sync::Arc;
use anyhow::Result;
use assistant_tool::ToolWorkingSet;
use assistant_tool::{Tool, ToolWorkingSet};
use collections::HashMap;
use futures::future::Shared;
use futures::FutureExt as _;
@ -10,6 +10,7 @@ use language_model::{
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
LanguageModelToolUseId, MessageContent, Role,
};
use scripting_tool::ScriptingTool;
use crate::thread::MessageId;
use crate::thread_store::SerializedMessage;
@ -25,6 +26,7 @@ pub struct ToolUse {
#[derive(Debug, Clone)]
pub enum ToolUseStatus {
NeedsConfirmation,
Pending,
Running,
Finished(SharedString),
@ -163,16 +165,19 @@ impl ToolUseState {
}
if let Some(pending_tool_use) = self.pending_tool_uses_by_id.get(&tool_use.id) {
return match pending_tool_use.status {
match pending_tool_use.status {
PendingToolUseStatus::Idle => ToolUseStatus::Pending,
PendingToolUseStatus::NeedsConfirmation { .. } => {
ToolUseStatus::NeedsConfirmation
}
PendingToolUseStatus::Running { .. } => ToolUseStatus::Running,
PendingToolUseStatus::Error(ref err) => {
ToolUseStatus::Error(err.clone().into())
}
};
}
} else {
ToolUseStatus::Pending
}
ToolUseStatus::Pending
})();
tool_uses.push(ToolUse {
@ -195,6 +200,8 @@ impl ToolUseState {
) -> SharedString {
if let Some(tool) = self.tools.tool(tool_name, cx) {
tool.ui_text(input).into()
} else if tool_name == ScriptingTool::NAME {
"Run Lua Script".into()
} else {
"Unknown tool".into()
}
@ -272,6 +279,28 @@ impl ToolUseState {
}
}
pub fn confirm_tool_use(
&mut self,
tool_use_id: LanguageModelToolUseId,
ui_text: impl Into<Arc<str>>,
input: serde_json::Value,
messages: Arc<Vec<LanguageModelRequestMessage>>,
tool_type: ToolType,
) {
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
let ui_text = ui_text.into();
tool_use.ui_text = ui_text.clone();
let confirmation = Confirmation {
tool_use_id,
input,
messages,
tool_type,
ui_text,
};
tool_use.status = PendingToolUseStatus::NeedsConfirmation(Arc::new(confirmation));
}
}
pub fn insert_tool_output(
&mut self,
tool_use_id: LanguageModelToolUseId,
@ -369,9 +398,25 @@ pub struct PendingToolUse {
pub status: PendingToolUseStatus,
}
#[derive(Debug, Clone)]
pub enum ToolType {
ScriptingTool,
NonScriptingTool(Arc<dyn Tool>),
}
#[derive(Debug, Clone)]
pub struct Confirmation {
pub tool_use_id: LanguageModelToolUseId,
pub input: serde_json::Value,
pub ui_text: Arc<str>,
pub messages: Arc<Vec<LanguageModelRequestMessage>>,
pub tool_type: ToolType,
}
#[derive(Debug, Clone)]
pub enum PendingToolUseStatus {
Idle,
NeedsConfirmation(Arc<Confirmation>),
Running { _task: Shared<Task<()>> },
Error(#[allow(unused)] Arc<str>),
}
@ -384,4 +429,8 @@ impl PendingToolUseStatus {
pub fn is_error(&self) -> bool {
matches!(self, PendingToolUseStatus::Error(_))
}
pub fn needs_confirmation(&self) -> bool {
matches!(self, PendingToolUseStatus::NeedsConfirmation { .. })
}
}