Remove Lua scripting tool (#27388)

We decided to take this out for now. It doesn't seem necessary, and it
complicates the code a lot. We can always put it back later if desired.

Release Notes:

- N/A
This commit is contained in:
Richard Feldman 2025-03-24 15:58:07 -04:00 committed by GitHub
parent 5465198d0d
commit 5d05c4aa70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 52 additions and 2059 deletions

View file

@ -3,8 +3,9 @@ use crate::thread::{
ThreadEvent, ThreadFeedback,
};
use crate::thread_store::ThreadStore;
use crate::tool_use::{PendingToolUseStatus, ToolType, ToolUse, ToolUseStatus};
use crate::tool_use::{PendingToolUseStatus, ToolUse, ToolUseStatus};
use crate::ui::ContextPill;
use collections::HashMap;
use editor::{Editor, MultiBuffer};
use gpui::{
@ -16,7 +17,6 @@ use gpui::{
use language::{Buffer, LanguageRegistry};
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
use markdown::{Markdown, MarkdownStyle};
use scripting_tool::{ScriptingTool, ScriptingToolInput};
use settings::Settings as _;
use std::sync::Arc;
use std::time::Duration;
@ -37,7 +37,6 @@ pub struct ActiveThread {
messages: Vec<MessageId>,
list_state: ListState,
rendered_messages_by_id: HashMap<MessageId, RenderedMessage>,
rendered_scripting_tool_uses: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
rendered_tool_use_labels: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
editing_message: Option<(MessageId, EditMessageState)>,
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
@ -233,7 +232,6 @@ impl ActiveThread {
save_thread_task: None,
messages: Vec::new(),
rendered_messages_by_id: HashMap::default(),
rendered_scripting_tool_uses: HashMap::default(),
rendered_tool_use_labels: HashMap::default(),
expanded_tool_uses: HashMap::default(),
expanded_thinking_segments: HashMap::default(),
@ -260,26 +258,6 @@ impl ActiveThread {
cx,
);
}
for tool_use in thread
.read(cx)
.scripting_tool_uses_for_message(message.id, cx)
{
this.render_tool_use_label_markdown(
tool_use.id.clone(),
tool_use.ui_text.clone(),
window,
cx,
);
this.render_scripting_tool_use_markdown(
tool_use.id.clone(),
tool_use.ui_text.as_ref(),
tool_use.input.clone(),
window,
cx,
);
}
}
this
@ -360,36 +338,6 @@ impl ActiveThread {
self.rendered_messages_by_id.remove(id);
}
/// Renders the input of a scripting tool use to Markdown.
///
/// Does nothing if the tool use does not correspond to the scripting tool.
fn render_scripting_tool_use_markdown(
&mut self,
tool_use_id: LanguageModelToolUseId,
tool_name: &str,
tool_input: serde_json::Value,
window: &mut Window,
cx: &mut Context<Self>,
) {
if tool_name != ScriptingTool::NAME {
return;
}
let lua_script = serde_json::from_value::<ScriptingToolInput>(tool_input)
.map(|input| input.lua_script)
.unwrap_or_default();
let lua_script = render_markdown(
format!("```lua\n{lua_script}\n```").into(),
self.language_registry.clone(),
window,
cx,
);
self.rendered_scripting_tool_uses
.insert(tool_use_id, lua_script);
}
fn render_tool_use_label_markdown(
&mut self,
tool_use_id: LanguageModelToolUseId,
@ -476,13 +424,6 @@ impl ActiveThread {
window,
cx,
);
self.render_scripting_tool_use_markdown(
tool_use.id,
tool_use.name.as_ref(),
tool_use.input.clone(),
window,
cx,
);
}
}
ThreadEvent::ToolFinished {
@ -725,13 +666,9 @@ impl ActiveThread {
let checkpoint = thread.checkpoint_for_message(message_id);
let context = thread.context_for_message(message_id);
let tool_uses = thread.tool_uses_for_message(message_id, cx);
let scripting_tool_uses = thread.scripting_tool_uses_for_message(message_id, cx);
// Don't render user messages that are just there for returning tool results.
if message.role == Role::User
&& (thread.message_has_tool_results(message_id)
|| thread.message_has_scripting_tool_results(message_id))
{
if message.role == Role::User && thread.message_has_tool_results(message_id) {
return Empty.into_any();
}
@ -996,32 +933,23 @@ impl ActiveThread {
)
.child(div().p_2().child(message_content)),
),
Role::Assistant => {
v_flex()
.id(("message-container", ix))
.ml_2()
.pl_2()
.pr_4()
.border_l_1()
.border_color(cx.theme().colors().border_variant)
.child(message_content)
.when(
!tool_uses.is_empty() || !scripting_tool_uses.is_empty(),
|parent| {
parent.child(
v_flex()
.children(
tool_uses
.into_iter()
.map(|tool_use| self.render_tool_use(tool_use, cx)),
)
.children(scripting_tool_uses.into_iter().map(|tool_use| {
self.render_scripting_tool_use(tool_use, cx)
})),
)
},
Role::Assistant => v_flex()
.id(("message-container", ix))
.ml_2()
.pl_2()
.pr_4()
.border_l_1()
.border_color(cx.theme().colors().border_variant)
.child(message_content)
.when(!tool_uses.is_empty(), |parent| {
parent.child(
v_flex().children(
tool_uses
.into_iter()
.map(|tool_use| self.render_tool_use(tool_use, cx)),
),
)
}
}),
Role::System => div().id(("message-container", ix)).py_1().px_2().child(
v_flex()
.bg(colors.editor_background)
@ -1537,145 +1465,6 @@ impl ActiveThread {
)
}
fn render_scripting_tool_use(
&self,
tool_use: ToolUse,
cx: &mut Context<Self>,
) -> impl IntoElement {
let is_open = self
.expanded_tool_uses
.get(&tool_use.id)
.copied()
.unwrap_or_default();
div().px_2p5().child(
v_flex()
.gap_1()
.rounded_lg()
.border_1()
.border_color(cx.theme().colors().border)
.child(
h_flex()
.justify_between()
.py_0p5()
.pl_1()
.pr_2()
.bg(cx.theme().colors().editor_foreground.opacity(0.02))
.map(|element| {
if is_open {
element.border_b_1().rounded_t_md()
} else {
element.rounded_md()
}
})
.border_color(cx.theme().colors().border)
.child(
h_flex()
.gap_1()
.child(Disclosure::new("tool-use-disclosure", is_open).on_click(
cx.listener({
let tool_use_id = tool_use.id.clone();
move |this, _event, _window, _cx| {
let is_open = this
.expanded_tool_uses
.entry(tool_use_id.clone())
.or_insert(false);
*is_open = !*is_open;
}
}),
))
.child(
h_flex()
.gap_1p5()
.child(
Icon::new(IconName::Terminal)
.size(IconSize::XSmall)
.color(Color::Muted),
)
.child(
div()
.text_ui_sm(cx)
.children(
self.rendered_tool_use_labels
.get(&tool_use.id)
.cloned(),
)
.truncate(),
),
),
)
.child(
Label::new(match tool_use.status {
ToolUseStatus::Pending => "Pending",
ToolUseStatus::Running => "Running",
ToolUseStatus::Finished(_) => "Finished",
ToolUseStatus::Error(_) => "Error",
ToolUseStatus::NeedsConfirmation => "Asking Permission",
})
.size(LabelSize::XSmall)
.buffer_font(cx),
),
)
.map(|parent| {
if !is_open {
return parent;
}
let lua_script_markdown =
self.rendered_scripting_tool_uses.get(&tool_use.id).cloned();
parent.child(
v_flex()
.child(
v_flex()
.gap_0p5()
.py_1()
.px_2p5()
.border_b_1()
.border_color(cx.theme().colors().border)
.child(Label::new("Input:"))
.map(|parent| {
if let Some(markdown) = lua_script_markdown {
parent.child(markdown)
} else {
parent.child(Label::new(
"Failed to render script input to Markdown",
))
}
}),
)
.map(|parent| match tool_use.status {
ToolUseStatus::Finished(output) => parent.child(
v_flex()
.gap_0p5()
.py_1()
.px_2p5()
.child(Label::new("Result:"))
.child(Label::new(output)),
),
ToolUseStatus::Error(err) => parent.child(
v_flex()
.gap_0p5()
.py_1()
.px_2p5()
.child(Label::new("Error:"))
.child(Label::new(err)),
),
ToolUseStatus::Pending | ToolUseStatus::Running => parent,
ToolUseStatus::NeedsConfirmation => parent.child(
v_flex()
.gap_0p5()
.py_1()
.px_2p5()
.child(Label::new("Asking Permission")),
),
}),
)
}),
)
}
fn render_rules_item(&self, cx: &Context<Self>) -> AnyElement {
let Some(system_prompt_context) = self.thread.read(cx).system_prompt_context().as_ref()
else {
@ -1751,7 +1540,7 @@ impl ActiveThread {
c.ui_text.clone(),
c.input.clone(),
&c.messages,
c.tool_type.clone(),
c.tool.clone(),
cx,
);
});
@ -1761,13 +1550,12 @@ impl ActiveThread {
fn handle_deny_tool(
&mut self,
tool_use_id: LanguageModelToolUseId,
tool_type: ToolType,
_: &ClickEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
self.thread.update(cx, |thread, cx| {
thread.deny_tool_use(tool_use_id, tool_type, cx);
thread.deny_tool_use(tool_use_id, cx);
});
}
@ -1802,7 +1590,7 @@ impl ActiveThread {
thread
.tools_needing_confirmation()
.map(|(tool_type, tool)| {
.map(|tool| {
div()
.m_3()
.p_2()
@ -1844,7 +1632,6 @@ impl ActiveThread {
move |this, event, window, cx| {
this.handle_deny_tool(
tool_id.clone(),
tool_type.clone(),
event,
window,
cx,

View file

@ -23,7 +23,6 @@ use project::{Project, Worktree};
use prompt_store::{
AssistantSystemPromptContext, PromptBuilder, RulesFile, WorktreeInfoForSystemPrompt,
};
use scripting_tool::{ScriptingSession, ScriptingTool};
use serde::{Deserialize, Serialize};
use settings::Settings;
use util::{maybe, post_inc, ResultExt as _, TryFutureExt as _};
@ -34,7 +33,7 @@ use crate::thread_store::{
SerializedMessage, SerializedMessageSegment, SerializedThread, SerializedToolResult,
SerializedToolUse,
};
use crate::tool_use::{PendingToolUse, PendingToolUseStatus, ToolType, ToolUse, ToolUseState};
use crate::tool_use::{PendingToolUse, ToolUse, ToolUseState};
#[derive(Debug, Clone, Copy)]
pub enum RequestKind {
@ -188,8 +187,6 @@ pub struct Thread {
action_log: Entity<ActionLog>,
last_restore_checkpoint: Option<LastRestoreCheckpoint>,
pending_checkpoint: Option<ThreadCheckpoint>,
scripting_session: Entity<ScriptingSession>,
scripting_tool_use: ToolUseState,
initial_project_snapshot: Shared<Task<Option<Arc<ProjectSnapshot>>>>,
cumulative_token_usage: TokenUsage,
feedback: Option<ThreadFeedback>,
@ -221,8 +218,6 @@ impl Thread {
last_restore_checkpoint: None,
pending_checkpoint: None,
tool_use: ToolUseState::new(tools.clone()),
scripting_session: cx.new(|cx| ScriptingSession::new(project.clone(), cx)),
scripting_tool_use: ToolUseState::new(tools),
action_log: cx.new(|_| ActionLog::new()),
initial_project_snapshot: {
let project_snapshot = Self::project_snapshot(project, cx);
@ -251,14 +246,7 @@ impl Thread {
.unwrap_or(0),
);
let tool_use =
ToolUseState::from_serialized_messages(tools.clone(), &serialized.messages, |name| {
name != ScriptingTool::NAME
});
let scripting_tool_use =
ToolUseState::from_serialized_messages(tools.clone(), &serialized.messages, |name| {
name == ScriptingTool::NAME
});
let scripting_session = cx.new(|cx| ScriptingSession::new(project.clone(), cx));
ToolUseState::from_serialized_messages(tools.clone(), &serialized.messages, |_| true);
Self {
id,
@ -297,8 +285,6 @@ impl Thread {
tools,
tool_use,
action_log: cx.new(|_| ActionLog::new()),
scripting_session,
scripting_tool_use,
initial_project_snapshot: Task::ready(serialized.initial_project_snapshot).shared(),
// TODO: persist token usage?
cumulative_token_usage: TokenUsage::default(),
@ -357,37 +343,13 @@ impl Thread {
.pending_tool_uses()
.into_iter()
.find(|tool_use| &tool_use.id == id)
.or_else(|| {
self.scripting_tool_use
.pending_tool_uses()
.into_iter()
.find(|tool_use| &tool_use.id == id)
})
}
pub fn tools_needing_confirmation(&self) -> impl Iterator<Item = (ToolType, &PendingToolUse)> {
pub fn tools_needing_confirmation(&self) -> impl Iterator<Item = &PendingToolUse> {
self.tool_use
.pending_tool_uses()
.into_iter()
.filter_map(|tool_use| {
if let PendingToolUseStatus::NeedsConfirmation(confirmation) = &tool_use.status {
Some((confirmation.tool_type.clone(), tool_use))
} else {
None
}
})
.chain(
self.scripting_tool_use
.pending_tool_uses()
.into_iter()
.filter_map(|tool_use| {
if tool_use.status.needs_confirmation() {
Some((ToolType::ScriptingTool, tool_use))
} else {
None
}
}),
)
.filter(|tool_use| tool_use.status.needs_confirmation())
}
pub fn checkpoint_for_message(&self, id: MessageId) -> Option<ThreadCheckpoint> {
@ -520,25 +482,18 @@ impl Thread {
/// Returns whether all of the tool uses have finished running.
pub fn all_tools_finished(&self) -> bool {
let mut all_pending_tool_uses = self
.tool_use
.pending_tool_uses()
.into_iter()
.chain(self.scripting_tool_use.pending_tool_uses());
// 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.
all_pending_tool_uses.all(|tool_use| tool_use.status.is_error())
self.tool_use
.pending_tool_uses()
.iter()
.all(|tool_use| tool_use.status.is_error())
}
pub fn tool_uses_for_message(&self, id: MessageId, cx: &App) -> Vec<ToolUse> {
self.tool_use.tool_uses_for_message(id, cx)
}
pub fn scripting_tool_uses_for_message(&self, id: MessageId, cx: &App) -> Vec<ToolUse> {
self.scripting_tool_use.tool_uses_for_message(id, cx)
}
pub fn tool_results_for_message(&self, id: MessageId) -> Vec<&LanguageModelToolResult> {
self.tool_use.tool_results_for_message(id)
}
@ -547,21 +502,10 @@ impl Thread {
self.tool_use.tool_result(id)
}
pub fn scripting_tool_results_for_message(
&self,
id: MessageId,
) -> Vec<&LanguageModelToolResult> {
self.scripting_tool_use.tool_results_for_message(id)
}
pub fn message_has_tool_results(&self, message_id: MessageId) -> bool {
self.tool_use.message_has_tool_results(message_id)
}
pub fn message_has_scripting_tool_results(&self, message_id: MessageId) -> bool {
self.scripting_tool_use.message_has_tool_results(message_id)
}
pub fn insert_user_message(
&mut self,
text: impl Into<String>,
@ -682,7 +626,6 @@ impl Thread {
tool_uses: this
.tool_uses_for_message(message.id, cx)
.into_iter()
.chain(this.scripting_tool_uses_for_message(message.id, cx))
.map(|tool_use| SerializedToolUse {
id: tool_use.id,
name: tool_use.name,
@ -692,7 +635,6 @@ impl Thread {
tool_results: this
.tool_results_for_message(message.id)
.into_iter()
.chain(this.scripting_tool_results_for_message(message.id))
.map(|tool_result| SerializedToolResult {
tool_use_id: tool_result.tool_use_id.clone(),
is_error: tool_result.is_error,
@ -825,15 +767,6 @@ impl Thread {
let mut request = self.to_completion_request(request_kind, cx);
request.tools = {
let mut tools = Vec::new();
if self.tools.is_scripting_tool_enabled() {
tools.push(LanguageModelRequestTool {
name: ScriptingTool::NAME.into(),
description: ScriptingTool::DESCRIPTION.into(),
input_schema: ScriptingTool::input_schema(),
});
}
tools.extend(self.tools().enabled_tools(cx).into_iter().map(|tool| {
LanguageModelRequestTool {
name: tool.name(),
@ -894,8 +827,6 @@ impl Thread {
RequestKind::Chat => {
self.tool_use
.attach_tool_results(message.id, &mut request_message);
self.scripting_tool_use
.attach_tool_results(message.id, &mut request_message);
}
RequestKind::Summarize => {
// We don't care about tool use during summarization.
@ -912,8 +843,6 @@ impl Thread {
RequestKind::Chat => {
self.tool_use
.attach_tool_uses(message.id, &mut request_message);
self.scripting_tool_use
.attach_tool_uses(message.id, &mut request_message);
}
RequestKind::Summarize => {
// We don't care about tool use during summarization.
@ -1060,19 +989,11 @@ impl Thread {
.iter()
.rfind(|message| message.role == Role::Assistant)
{
if tool_use.name.as_ref() == ScriptingTool::NAME {
thread.scripting_tool_use.request_tool_use(
last_assistant_message.id,
tool_use,
cx,
);
} else {
thread.tool_use.request_tool_use(
last_assistant_message.id,
tool_use,
cx,
);
}
thread.tool_use.request_tool_use(
last_assistant_message.id,
tool_use,
cx,
);
}
}
}
@ -1237,7 +1158,7 @@ impl Thread {
tool_use.ui_text.clone(),
tool_use.input.clone(),
messages.clone(),
ToolType::NonScriptingTool(tool),
tool,
);
} else {
self.run_tool(
@ -1245,7 +1166,7 @@ impl Thread {
tool_use.ui_text.clone(),
tool_use.input.clone(),
&messages,
ToolType::NonScriptingTool(tool),
tool,
cx,
);
}
@ -1255,33 +1176,13 @@ impl Thread {
tool_use.ui_text.clone(),
tool_use.input.clone(),
&messages,
ToolType::NonScriptingTool(tool),
tool,
cx,
);
}
}
let pending_scripting_tool_uses = self
.scripting_tool_use
.pending_tool_uses()
.into_iter()
.filter(|tool_use| tool_use.status.is_idle())
.cloned()
.collect::<Vec<_>>();
for scripting_tool_use in pending_scripting_tool_uses.iter() {
self.scripting_tool_use.confirm_tool_use(
scripting_tool_use.id.clone(),
scripting_tool_use.ui_text.clone(),
scripting_tool_use.input.clone(),
messages.clone(),
ToolType::ScriptingTool,
);
}
pending_tool_uses
.into_iter()
.chain(pending_scripting_tool_uses)
}
pub fn run_tool(
@ -1290,21 +1191,12 @@ impl Thread {
ui_text: impl Into<SharedString>,
input: serde_json::Value,
messages: &[LanguageModelRequestMessage],
tool_type: ToolType,
tool: Arc<dyn Tool>,
cx: &mut Context<'_, Thread>,
) {
match tool_type {
ToolType::ScriptingTool => {
let task = self.spawn_scripting_tool_use(tool_use_id.clone(), input, cx);
self.scripting_tool_use
.run_pending_tool(tool_use_id, ui_text.into(), task);
}
ToolType::NonScriptingTool(tool) => {
let task = self.spawn_tool_use(tool_use_id.clone(), messages, input, tool, cx);
self.tool_use
.run_pending_tool(tool_use_id, ui_text.into(), task);
}
}
let task = self.spawn_tool_use(tool_use_id.clone(), messages, input, tool, cx);
self.tool_use
.run_pending_tool(tool_use_id, ui_text.into(), task);
}
fn spawn_tool_use(
@ -1344,60 +1236,6 @@ impl Thread {
})
}
fn spawn_scripting_tool_use(
&mut self,
tool_use_id: LanguageModelToolUseId,
input: serde_json::Value,
cx: &mut Context<Thread>,
) -> Task<()> {
let task = match ScriptingTool::deserialize_input(input) {
Err(err) => Task::ready(Err(err.into())),
Ok(input) => {
let (script_id, script_task) =
self.scripting_session.update(cx, move |session, cx| {
session.run_script(input.lua_script, cx)
});
let session = self.scripting_session.clone();
cx.spawn(async move |_, cx| {
script_task.await;
let message = session.read_with(cx, |session, _cx| {
// Using a id to get the script output seems impractical.
// Why not just include it in the Task result?
// This is because we'll later report the script state as it runs,
session
.get(script_id)
.output_message_for_llm()
.expect("Script shouldn't still be running")
})?;
Ok(message)
})
}
};
cx.spawn({
let tool_use_id = tool_use_id.clone();
async move |thread, cx| {
let output = task.await;
thread
.update(cx, |thread, cx| {
let pending_tool_use = thread
.scripting_tool_use
.insert_tool_output(tool_use_id.clone(), output);
cx.emit(ThreadEvent::ToolFinished {
tool_use_id,
pending_tool_use,
canceled: false,
});
})
.ok();
}
})
}
pub fn attach_tool_results(
&mut self,
updated_context: Vec<ContextSnapshot>,
@ -1654,22 +1492,12 @@ impl Thread {
self.cumulative_token_usage.clone()
}
pub fn deny_tool_use(
&mut self,
tool_use_id: LanguageModelToolUseId,
tool_type: ToolType,
cx: &mut Context<Self>,
) {
pub fn deny_tool_use(&mut self, tool_use_id: LanguageModelToolUseId, cx: &mut Context<Self>) {
let err = Err(anyhow::anyhow!(
"Permission to run tool action denied by user"
));
if let ToolType::ScriptingTool = tool_type {
self.scripting_tool_use
.insert_tool_output(tool_use_id.clone(), err);
} else {
self.tool_use.insert_tool_output(tool_use_id.clone(), err);
}
self.tool_use.insert_tool_output(tool_use_id.clone(), err);
cx.emit(ThreadEvent::ToolFinished {
tool_use_id,

View file

@ -4,7 +4,6 @@ use assistant_settings::{AgentProfile, AssistantSettings};
use assistant_tool::{ToolSource, ToolWorkingSet};
use gpui::{Entity, Subscription};
use indexmap::IndexMap;
use scripting_tool::ScriptingTool;
use settings::{Settings as _, SettingsStore};
use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};
@ -52,7 +51,6 @@ impl ToolSelector {
let tools = tool_set.clone();
move |_window, cx| {
tools.disable_source(ToolSource::Native, cx);
tools.disable_scripting_tool();
tools.enable(
ToolSource::Native,
&profile
@ -61,10 +59,6 @@ impl ToolSelector {
.filter_map(|(tool, enabled)| enabled.then(|| tool.clone()))
.collect::<Vec<_>>(),
);
if profile.tools.contains_key(ScriptingTool::NAME) {
tools.enable_scripting_tool();
}
}
});
}
@ -98,11 +92,6 @@ impl ToolSelector {
.collect::<Vec<_>>();
if ToolSource::Native == source {
tools.push((
ToolSource::Native,
ScriptingTool::NAME.into(),
tool_set.is_scripting_tool_enabled(),
));
tools.sort_by(|(_, name_a, _), (_, name_b, _)| name_a.cmp(name_b));
}
@ -136,18 +125,10 @@ impl ToolSelector {
menu = menu.toggleable_entry(name.clone(), is_enabled, icon_position, None, {
let tools = tool_set.clone();
move |_window, _cx| {
if name.as_ref() == ScriptingTool::NAME {
if is_enabled {
tools.disable_scripting_tool();
} else {
tools.enable_scripting_tool();
}
if is_enabled {
tools.disable(source.clone(), &[name.clone()]);
} else {
if is_enabled {
tools.disable(source.clone(), &[name.clone()]);
} else {
tools.enable(source.clone(), &[name.clone()]);
}
tools.enable(source.clone(), &[name.clone()]);
}
}
});

View file

@ -10,7 +10,6 @@ use language_model::{
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
LanguageModelToolUseId, MessageContent, Role,
};
use scripting_tool::ScriptingTool;
use crate::thread::MessageId;
use crate::thread_store::SerializedMessage;
@ -200,8 +199,6 @@ 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()
}
@ -285,7 +282,7 @@ impl ToolUseState {
ui_text: impl Into<Arc<str>>,
input: serde_json::Value,
messages: Arc<Vec<LanguageModelRequestMessage>>,
tool_type: ToolType,
tool: Arc<dyn Tool>,
) {
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
let ui_text = ui_text.into();
@ -294,7 +291,7 @@ impl ToolUseState {
tool_use_id,
input,
messages,
tool_type,
tool,
ui_text,
};
tool_use.status = PendingToolUseStatus::NeedsConfirmation(Arc::new(confirmation));
@ -398,19 +395,13 @@ 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,
pub tool: Arc<dyn Tool>,
}
#[derive(Debug, Clone)]