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:
parent
5465198d0d
commit
5d05c4aa70
14 changed files with 52 additions and 2059 deletions
90
Cargo.lock
generated
90
Cargo.lock
generated
|
@ -492,7 +492,6 @@ dependencies = [
|
||||||
"proto",
|
"proto",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rope",
|
"rope",
|
||||||
"scripting_tool",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
|
@ -4521,12 +4520,6 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_home"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
@ -7931,25 +7924,6 @@ dependencies = [
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lua-src"
|
|
||||||
version = "547.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1edaf29e3517b49b8b746701e5648ccb5785cde1c119062cbabbc5d5cd115e42"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "luajit-src"
|
|
||||||
version = "210.5.12+a4f56a4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b3a8e7962a5368d5f264d045a5a255e90f9aa3fc1941ae15a8d2940d42cac671"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"which 7.0.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lyon"
|
name = "lyon"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -8365,34 +8339,6 @@ dependencies = [
|
||||||
"strum",
|
"strum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mlua"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b"
|
|
||||||
dependencies = [
|
|
||||||
"bstr",
|
|
||||||
"either",
|
|
||||||
"futures-util",
|
|
||||||
"mlua-sys",
|
|
||||||
"num-traits",
|
|
||||||
"parking_lot",
|
|
||||||
"rustc-hash 2.1.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mlua-sys"
|
|
||||||
version = "0.6.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1901c1a635a22fe9250ffcc4fcc937c16b47c2e9e71adba8784af8bca1f69594"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"lua-src",
|
|
||||||
"luajit-src",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "msvc_spectre_libs"
|
name = "msvc_spectre_libs"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -12201,30 +12147,6 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
|
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scripting_tool"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"buffer_diff",
|
|
||||||
"clock",
|
|
||||||
"collections",
|
|
||||||
"futures 0.3.31",
|
|
||||||
"gpui",
|
|
||||||
"language",
|
|
||||||
"log",
|
|
||||||
"mlua",
|
|
||||||
"parking_lot",
|
|
||||||
"project",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"regex",
|
|
||||||
"schemars",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"settings",
|
|
||||||
"util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scrypt"
|
name = "scrypt"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -16186,18 +16108,6 @@ dependencies = [
|
||||||
"winsafe",
|
"winsafe",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "which"
|
|
||||||
version = "7.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"env_home",
|
|
||||||
"rustix",
|
|
||||||
"winsafe",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.5.2"
|
version = "1.5.2"
|
||||||
|
|
|
@ -124,7 +124,6 @@ members = [
|
||||||
"crates/rope",
|
"crates/rope",
|
||||||
"crates/rpc",
|
"crates/rpc",
|
||||||
"crates/schema_generator",
|
"crates/schema_generator",
|
||||||
"crates/scripting_tool",
|
|
||||||
"crates/search",
|
"crates/search",
|
||||||
"crates/semantic_index",
|
"crates/semantic_index",
|
||||||
"crates/semantic_version",
|
"crates/semantic_version",
|
||||||
|
@ -329,7 +328,6 @@ reqwest_client = { path = "crates/reqwest_client" }
|
||||||
rich_text = { path = "crates/rich_text" }
|
rich_text = { path = "crates/rich_text" }
|
||||||
rope = { path = "crates/rope" }
|
rope = { path = "crates/rope" }
|
||||||
rpc = { path = "crates/rpc" }
|
rpc = { path = "crates/rpc" }
|
||||||
scripting_tool = { path = "crates/scripting_tool" }
|
|
||||||
search = { path = "crates/search" }
|
search = { path = "crates/search" }
|
||||||
semantic_index = { path = "crates/semantic_index" }
|
semantic_index = { path = "crates/semantic_index" }
|
||||||
semantic_version = { path = "crates/semantic_version" }
|
semantic_version = { path = "crates/semantic_version" }
|
||||||
|
|
|
@ -62,7 +62,6 @@ prompt_library.workspace = true
|
||||||
prompt_store.workspace = true
|
prompt_store.workspace = true
|
||||||
proto.workspace = true
|
proto.workspace = true
|
||||||
rope.workspace = true
|
rope.workspace = true
|
||||||
scripting_tool.workspace = true
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
|
|
|
@ -3,8 +3,9 @@ use crate::thread::{
|
||||||
ThreadEvent, ThreadFeedback,
|
ThreadEvent, ThreadFeedback,
|
||||||
};
|
};
|
||||||
use crate::thread_store::ThreadStore;
|
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 crate::ui::ContextPill;
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{Editor, MultiBuffer};
|
use editor::{Editor, MultiBuffer};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
@ -16,7 +17,6 @@ use gpui::{
|
||||||
use language::{Buffer, LanguageRegistry};
|
use language::{Buffer, LanguageRegistry};
|
||||||
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
|
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
|
||||||
use markdown::{Markdown, MarkdownStyle};
|
use markdown::{Markdown, MarkdownStyle};
|
||||||
use scripting_tool::{ScriptingTool, ScriptingToolInput};
|
|
||||||
use settings::Settings as _;
|
use settings::Settings as _;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -37,7 +37,6 @@ pub struct ActiveThread {
|
||||||
messages: Vec<MessageId>,
|
messages: Vec<MessageId>,
|
||||||
list_state: ListState,
|
list_state: ListState,
|
||||||
rendered_messages_by_id: HashMap<MessageId, RenderedMessage>,
|
rendered_messages_by_id: HashMap<MessageId, RenderedMessage>,
|
||||||
rendered_scripting_tool_uses: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
|
|
||||||
rendered_tool_use_labels: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
|
rendered_tool_use_labels: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
|
||||||
editing_message: Option<(MessageId, EditMessageState)>,
|
editing_message: Option<(MessageId, EditMessageState)>,
|
||||||
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
|
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
|
||||||
|
@ -233,7 +232,6 @@ impl ActiveThread {
|
||||||
save_thread_task: None,
|
save_thread_task: None,
|
||||||
messages: Vec::new(),
|
messages: Vec::new(),
|
||||||
rendered_messages_by_id: HashMap::default(),
|
rendered_messages_by_id: HashMap::default(),
|
||||||
rendered_scripting_tool_uses: HashMap::default(),
|
|
||||||
rendered_tool_use_labels: HashMap::default(),
|
rendered_tool_use_labels: HashMap::default(),
|
||||||
expanded_tool_uses: HashMap::default(),
|
expanded_tool_uses: HashMap::default(),
|
||||||
expanded_thinking_segments: HashMap::default(),
|
expanded_thinking_segments: HashMap::default(),
|
||||||
|
@ -260,26 +258,6 @@ impl ActiveThread {
|
||||||
cx,
|
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
|
this
|
||||||
|
@ -360,36 +338,6 @@ impl ActiveThread {
|
||||||
self.rendered_messages_by_id.remove(id);
|
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(
|
fn render_tool_use_label_markdown(
|
||||||
&mut self,
|
&mut self,
|
||||||
tool_use_id: LanguageModelToolUseId,
|
tool_use_id: LanguageModelToolUseId,
|
||||||
|
@ -476,13 +424,6 @@ impl ActiveThread {
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
self.render_scripting_tool_use_markdown(
|
|
||||||
tool_use.id,
|
|
||||||
tool_use.name.as_ref(),
|
|
||||||
tool_use.input.clone(),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ThreadEvent::ToolFinished {
|
ThreadEvent::ToolFinished {
|
||||||
|
@ -725,13 +666,9 @@ impl ActiveThread {
|
||||||
let checkpoint = thread.checkpoint_for_message(message_id);
|
let checkpoint = thread.checkpoint_for_message(message_id);
|
||||||
let context = thread.context_for_message(message_id);
|
let context = thread.context_for_message(message_id);
|
||||||
let tool_uses = thread.tool_uses_for_message(message_id, cx);
|
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.
|
// Don't render user messages that are just there for returning tool results.
|
||||||
if message.role == Role::User
|
if message.role == Role::User && thread.message_has_tool_results(message_id) {
|
||||||
&& (thread.message_has_tool_results(message_id)
|
|
||||||
|| thread.message_has_scripting_tool_results(message_id))
|
|
||||||
{
|
|
||||||
return Empty.into_any();
|
return Empty.into_any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,32 +933,23 @@ impl ActiveThread {
|
||||||
)
|
)
|
||||||
.child(div().p_2().child(message_content)),
|
.child(div().p_2().child(message_content)),
|
||||||
),
|
),
|
||||||
Role::Assistant => {
|
Role::Assistant => v_flex()
|
||||||
v_flex()
|
.id(("message-container", ix))
|
||||||
.id(("message-container", ix))
|
.ml_2()
|
||||||
.ml_2()
|
.pl_2()
|
||||||
.pl_2()
|
.pr_4()
|
||||||
.pr_4()
|
.border_l_1()
|
||||||
.border_l_1()
|
.border_color(cx.theme().colors().border_variant)
|
||||||
.border_color(cx.theme().colors().border_variant)
|
.child(message_content)
|
||||||
.child(message_content)
|
.when(!tool_uses.is_empty(), |parent| {
|
||||||
.when(
|
parent.child(
|
||||||
!tool_uses.is_empty() || !scripting_tool_uses.is_empty(),
|
v_flex().children(
|
||||||
|parent| {
|
tool_uses
|
||||||
parent.child(
|
.into_iter()
|
||||||
v_flex()
|
.map(|tool_use| self.render_tool_use(tool_use, cx)),
|
||||||
.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::System => div().id(("message-container", ix)).py_1().px_2().child(
|
Role::System => div().id(("message-container", ix)).py_1().px_2().child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.bg(colors.editor_background)
|
.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 {
|
fn render_rules_item(&self, cx: &Context<Self>) -> AnyElement {
|
||||||
let Some(system_prompt_context) = self.thread.read(cx).system_prompt_context().as_ref()
|
let Some(system_prompt_context) = self.thread.read(cx).system_prompt_context().as_ref()
|
||||||
else {
|
else {
|
||||||
|
@ -1751,7 +1540,7 @@ impl ActiveThread {
|
||||||
c.ui_text.clone(),
|
c.ui_text.clone(),
|
||||||
c.input.clone(),
|
c.input.clone(),
|
||||||
&c.messages,
|
&c.messages,
|
||||||
c.tool_type.clone(),
|
c.tool.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1761,13 +1550,12 @@ impl ActiveThread {
|
||||||
fn handle_deny_tool(
|
fn handle_deny_tool(
|
||||||
&mut self,
|
&mut self,
|
||||||
tool_use_id: LanguageModelToolUseId,
|
tool_use_id: LanguageModelToolUseId,
|
||||||
tool_type: ToolType,
|
|
||||||
_: &ClickEvent,
|
_: &ClickEvent,
|
||||||
_window: &mut Window,
|
_window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
self.thread.update(cx, |thread, cx| {
|
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
|
thread
|
||||||
.tools_needing_confirmation()
|
.tools_needing_confirmation()
|
||||||
.map(|(tool_type, tool)| {
|
.map(|tool| {
|
||||||
div()
|
div()
|
||||||
.m_3()
|
.m_3()
|
||||||
.p_2()
|
.p_2()
|
||||||
|
@ -1844,7 +1632,6 @@ impl ActiveThread {
|
||||||
move |this, event, window, cx| {
|
move |this, event, window, cx| {
|
||||||
this.handle_deny_tool(
|
this.handle_deny_tool(
|
||||||
tool_id.clone(),
|
tool_id.clone(),
|
||||||
tool_type.clone(),
|
|
||||||
event,
|
event,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -23,7 +23,6 @@ use project::{Project, Worktree};
|
||||||
use prompt_store::{
|
use prompt_store::{
|
||||||
AssistantSystemPromptContext, PromptBuilder, RulesFile, WorktreeInfoForSystemPrompt,
|
AssistantSystemPromptContext, PromptBuilder, RulesFile, WorktreeInfoForSystemPrompt,
|
||||||
};
|
};
|
||||||
use scripting_tool::{ScriptingSession, ScriptingTool};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use util::{maybe, post_inc, ResultExt as _, TryFutureExt as _};
|
use util::{maybe, post_inc, ResultExt as _, TryFutureExt as _};
|
||||||
|
@ -34,7 +33,7 @@ use crate::thread_store::{
|
||||||
SerializedMessage, SerializedMessageSegment, SerializedThread, SerializedToolResult,
|
SerializedMessage, SerializedMessageSegment, SerializedThread, SerializedToolResult,
|
||||||
SerializedToolUse,
|
SerializedToolUse,
|
||||||
};
|
};
|
||||||
use crate::tool_use::{PendingToolUse, PendingToolUseStatus, ToolType, ToolUse, ToolUseState};
|
use crate::tool_use::{PendingToolUse, ToolUse, ToolUseState};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum RequestKind {
|
pub enum RequestKind {
|
||||||
|
@ -188,8 +187,6 @@ pub struct Thread {
|
||||||
action_log: Entity<ActionLog>,
|
action_log: Entity<ActionLog>,
|
||||||
last_restore_checkpoint: Option<LastRestoreCheckpoint>,
|
last_restore_checkpoint: Option<LastRestoreCheckpoint>,
|
||||||
pending_checkpoint: Option<ThreadCheckpoint>,
|
pending_checkpoint: Option<ThreadCheckpoint>,
|
||||||
scripting_session: Entity<ScriptingSession>,
|
|
||||||
scripting_tool_use: ToolUseState,
|
|
||||||
initial_project_snapshot: Shared<Task<Option<Arc<ProjectSnapshot>>>>,
|
initial_project_snapshot: Shared<Task<Option<Arc<ProjectSnapshot>>>>,
|
||||||
cumulative_token_usage: TokenUsage,
|
cumulative_token_usage: TokenUsage,
|
||||||
feedback: Option<ThreadFeedback>,
|
feedback: Option<ThreadFeedback>,
|
||||||
|
@ -221,8 +218,6 @@ impl Thread {
|
||||||
last_restore_checkpoint: None,
|
last_restore_checkpoint: None,
|
||||||
pending_checkpoint: None,
|
pending_checkpoint: None,
|
||||||
tool_use: ToolUseState::new(tools.clone()),
|
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()),
|
action_log: cx.new(|_| ActionLog::new()),
|
||||||
initial_project_snapshot: {
|
initial_project_snapshot: {
|
||||||
let project_snapshot = Self::project_snapshot(project, cx);
|
let project_snapshot = Self::project_snapshot(project, cx);
|
||||||
|
@ -251,14 +246,7 @@ impl Thread {
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
);
|
);
|
||||||
let tool_use =
|
let tool_use =
|
||||||
ToolUseState::from_serialized_messages(tools.clone(), &serialized.messages, |name| {
|
ToolUseState::from_serialized_messages(tools.clone(), &serialized.messages, |_| true);
|
||||||
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));
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
@ -297,8 +285,6 @@ impl Thread {
|
||||||
tools,
|
tools,
|
||||||
tool_use,
|
tool_use,
|
||||||
action_log: cx.new(|_| ActionLog::new()),
|
action_log: cx.new(|_| ActionLog::new()),
|
||||||
scripting_session,
|
|
||||||
scripting_tool_use,
|
|
||||||
initial_project_snapshot: Task::ready(serialized.initial_project_snapshot).shared(),
|
initial_project_snapshot: Task::ready(serialized.initial_project_snapshot).shared(),
|
||||||
// TODO: persist token usage?
|
// TODO: persist token usage?
|
||||||
cumulative_token_usage: TokenUsage::default(),
|
cumulative_token_usage: TokenUsage::default(),
|
||||||
|
@ -357,37 +343,13 @@ impl Thread {
|
||||||
.pending_tool_uses()
|
.pending_tool_uses()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|tool_use| &tool_use.id == id)
|
.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
|
self.tool_use
|
||||||
.pending_tool_uses()
|
.pending_tool_uses()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|tool_use| {
|
.filter(|tool_use| tool_use.status.needs_confirmation())
|
||||||
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
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkpoint_for_message(&self, id: MessageId) -> Option<ThreadCheckpoint> {
|
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.
|
/// Returns whether all of the tool uses have finished running.
|
||||||
pub fn all_tools_finished(&self) -> bool {
|
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
|
// 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.
|
// 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> {
|
pub fn tool_uses_for_message(&self, id: MessageId, cx: &App) -> Vec<ToolUse> {
|
||||||
self.tool_use.tool_uses_for_message(id, cx)
|
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> {
|
pub fn tool_results_for_message(&self, id: MessageId) -> Vec<&LanguageModelToolResult> {
|
||||||
self.tool_use.tool_results_for_message(id)
|
self.tool_use.tool_results_for_message(id)
|
||||||
}
|
}
|
||||||
|
@ -547,21 +502,10 @@ impl Thread {
|
||||||
self.tool_use.tool_result(id)
|
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 {
|
pub fn message_has_tool_results(&self, message_id: MessageId) -> bool {
|
||||||
self.tool_use.message_has_tool_results(message_id)
|
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(
|
pub fn insert_user_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
text: impl Into<String>,
|
text: impl Into<String>,
|
||||||
|
@ -682,7 +626,6 @@ impl Thread {
|
||||||
tool_uses: this
|
tool_uses: this
|
||||||
.tool_uses_for_message(message.id, cx)
|
.tool_uses_for_message(message.id, cx)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(this.scripting_tool_uses_for_message(message.id, cx))
|
|
||||||
.map(|tool_use| SerializedToolUse {
|
.map(|tool_use| SerializedToolUse {
|
||||||
id: tool_use.id,
|
id: tool_use.id,
|
||||||
name: tool_use.name,
|
name: tool_use.name,
|
||||||
|
@ -692,7 +635,6 @@ impl Thread {
|
||||||
tool_results: this
|
tool_results: this
|
||||||
.tool_results_for_message(message.id)
|
.tool_results_for_message(message.id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(this.scripting_tool_results_for_message(message.id))
|
|
||||||
.map(|tool_result| SerializedToolResult {
|
.map(|tool_result| SerializedToolResult {
|
||||||
tool_use_id: tool_result.tool_use_id.clone(),
|
tool_use_id: tool_result.tool_use_id.clone(),
|
||||||
is_error: tool_result.is_error,
|
is_error: tool_result.is_error,
|
||||||
|
@ -825,15 +767,6 @@ impl Thread {
|
||||||
let mut request = self.to_completion_request(request_kind, cx);
|
let mut request = self.to_completion_request(request_kind, cx);
|
||||||
request.tools = {
|
request.tools = {
|
||||||
let mut tools = Vec::new();
|
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| {
|
tools.extend(self.tools().enabled_tools(cx).into_iter().map(|tool| {
|
||||||
LanguageModelRequestTool {
|
LanguageModelRequestTool {
|
||||||
name: tool.name(),
|
name: tool.name(),
|
||||||
|
@ -894,8 +827,6 @@ impl Thread {
|
||||||
RequestKind::Chat => {
|
RequestKind::Chat => {
|
||||||
self.tool_use
|
self.tool_use
|
||||||
.attach_tool_results(message.id, &mut request_message);
|
.attach_tool_results(message.id, &mut request_message);
|
||||||
self.scripting_tool_use
|
|
||||||
.attach_tool_results(message.id, &mut request_message);
|
|
||||||
}
|
}
|
||||||
RequestKind::Summarize => {
|
RequestKind::Summarize => {
|
||||||
// We don't care about tool use during summarization.
|
// We don't care about tool use during summarization.
|
||||||
|
@ -912,8 +843,6 @@ impl Thread {
|
||||||
RequestKind::Chat => {
|
RequestKind::Chat => {
|
||||||
self.tool_use
|
self.tool_use
|
||||||
.attach_tool_uses(message.id, &mut request_message);
|
.attach_tool_uses(message.id, &mut request_message);
|
||||||
self.scripting_tool_use
|
|
||||||
.attach_tool_uses(message.id, &mut request_message);
|
|
||||||
}
|
}
|
||||||
RequestKind::Summarize => {
|
RequestKind::Summarize => {
|
||||||
// We don't care about tool use during summarization.
|
// We don't care about tool use during summarization.
|
||||||
|
@ -1060,19 +989,11 @@ impl Thread {
|
||||||
.iter()
|
.iter()
|
||||||
.rfind(|message| message.role == Role::Assistant)
|
.rfind(|message| message.role == Role::Assistant)
|
||||||
{
|
{
|
||||||
if tool_use.name.as_ref() == ScriptingTool::NAME {
|
thread.tool_use.request_tool_use(
|
||||||
thread.scripting_tool_use.request_tool_use(
|
last_assistant_message.id,
|
||||||
last_assistant_message.id,
|
tool_use,
|
||||||
tool_use,
|
cx,
|
||||||
cx,
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
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.ui_text.clone(),
|
||||||
tool_use.input.clone(),
|
tool_use.input.clone(),
|
||||||
messages.clone(),
|
messages.clone(),
|
||||||
ToolType::NonScriptingTool(tool),
|
tool,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.run_tool(
|
self.run_tool(
|
||||||
|
@ -1245,7 +1166,7 @@ impl Thread {
|
||||||
tool_use.ui_text.clone(),
|
tool_use.ui_text.clone(),
|
||||||
tool_use.input.clone(),
|
tool_use.input.clone(),
|
||||||
&messages,
|
&messages,
|
||||||
ToolType::NonScriptingTool(tool),
|
tool,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1255,33 +1176,13 @@ impl Thread {
|
||||||
tool_use.ui_text.clone(),
|
tool_use.ui_text.clone(),
|
||||||
tool_use.input.clone(),
|
tool_use.input.clone(),
|
||||||
&messages,
|
&messages,
|
||||||
ToolType::NonScriptingTool(tool),
|
tool,
|
||||||
cx,
|
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
|
pending_tool_uses
|
||||||
.into_iter()
|
|
||||||
.chain(pending_scripting_tool_uses)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tool(
|
pub fn run_tool(
|
||||||
|
@ -1290,21 +1191,12 @@ impl Thread {
|
||||||
ui_text: impl Into<SharedString>,
|
ui_text: impl Into<SharedString>,
|
||||||
input: serde_json::Value,
|
input: serde_json::Value,
|
||||||
messages: &[LanguageModelRequestMessage],
|
messages: &[LanguageModelRequestMessage],
|
||||||
tool_type: ToolType,
|
tool: Arc<dyn Tool>,
|
||||||
cx: &mut Context<'_, Thread>,
|
cx: &mut Context<'_, Thread>,
|
||||||
) {
|
) {
|
||||||
match tool_type {
|
let task = self.spawn_tool_use(tool_use_id.clone(), messages, input, tool, cx);
|
||||||
ToolType::ScriptingTool => {
|
self.tool_use
|
||||||
let task = self.spawn_scripting_tool_use(tool_use_id.clone(), input, cx);
|
.run_pending_tool(tool_use_id, ui_text.into(), task);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_tool_use(
|
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(
|
pub fn attach_tool_results(
|
||||||
&mut self,
|
&mut self,
|
||||||
updated_context: Vec<ContextSnapshot>,
|
updated_context: Vec<ContextSnapshot>,
|
||||||
|
@ -1654,22 +1492,12 @@ impl Thread {
|
||||||
self.cumulative_token_usage.clone()
|
self.cumulative_token_usage.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deny_tool_use(
|
pub fn deny_tool_use(&mut self, tool_use_id: LanguageModelToolUseId, cx: &mut Context<Self>) {
|
||||||
&mut self,
|
|
||||||
tool_use_id: LanguageModelToolUseId,
|
|
||||||
tool_type: ToolType,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) {
|
|
||||||
let err = Err(anyhow::anyhow!(
|
let err = Err(anyhow::anyhow!(
|
||||||
"Permission to run tool action denied by user"
|
"Permission to run tool action denied by user"
|
||||||
));
|
));
|
||||||
|
|
||||||
if let ToolType::ScriptingTool = tool_type {
|
self.tool_use.insert_tool_output(tool_use_id.clone(), err);
|
||||||
self.scripting_tool_use
|
|
||||||
.insert_tool_output(tool_use_id.clone(), err);
|
|
||||||
} else {
|
|
||||||
self.tool_use.insert_tool_output(tool_use_id.clone(), err);
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.emit(ThreadEvent::ToolFinished {
|
cx.emit(ThreadEvent::ToolFinished {
|
||||||
tool_use_id,
|
tool_use_id,
|
||||||
|
|
|
@ -4,7 +4,6 @@ use assistant_settings::{AgentProfile, AssistantSettings};
|
||||||
use assistant_tool::{ToolSource, ToolWorkingSet};
|
use assistant_tool::{ToolSource, ToolWorkingSet};
|
||||||
use gpui::{Entity, Subscription};
|
use gpui::{Entity, Subscription};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use scripting_tool::ScriptingTool;
|
|
||||||
use settings::{Settings as _, SettingsStore};
|
use settings::{Settings as _, SettingsStore};
|
||||||
use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};
|
use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};
|
||||||
|
|
||||||
|
@ -52,7 +51,6 @@ impl ToolSelector {
|
||||||
let tools = tool_set.clone();
|
let tools = tool_set.clone();
|
||||||
move |_window, cx| {
|
move |_window, cx| {
|
||||||
tools.disable_source(ToolSource::Native, cx);
|
tools.disable_source(ToolSource::Native, cx);
|
||||||
tools.disable_scripting_tool();
|
|
||||||
tools.enable(
|
tools.enable(
|
||||||
ToolSource::Native,
|
ToolSource::Native,
|
||||||
&profile
|
&profile
|
||||||
|
@ -61,10 +59,6 @@ impl ToolSelector {
|
||||||
.filter_map(|(tool, enabled)| enabled.then(|| tool.clone()))
|
.filter_map(|(tool, enabled)| enabled.then(|| tool.clone()))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if profile.tools.contains_key(ScriptingTool::NAME) {
|
|
||||||
tools.enable_scripting_tool();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -98,11 +92,6 @@ impl ToolSelector {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if ToolSource::Native == source {
|
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));
|
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, {
|
menu = menu.toggleable_entry(name.clone(), is_enabled, icon_position, None, {
|
||||||
let tools = tool_set.clone();
|
let tools = tool_set.clone();
|
||||||
move |_window, _cx| {
|
move |_window, _cx| {
|
||||||
if name.as_ref() == ScriptingTool::NAME {
|
if is_enabled {
|
||||||
if is_enabled {
|
tools.disable(source.clone(), &[name.clone()]);
|
||||||
tools.disable_scripting_tool();
|
|
||||||
} else {
|
|
||||||
tools.enable_scripting_tool();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if is_enabled {
|
tools.enable(source.clone(), &[name.clone()]);
|
||||||
tools.disable(source.clone(), &[name.clone()]);
|
|
||||||
} else {
|
|
||||||
tools.enable(source.clone(), &[name.clone()]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,6 @@ use language_model::{
|
||||||
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
|
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
|
||||||
LanguageModelToolUseId, MessageContent, Role,
|
LanguageModelToolUseId, MessageContent, Role,
|
||||||
};
|
};
|
||||||
use scripting_tool::ScriptingTool;
|
|
||||||
|
|
||||||
use crate::thread::MessageId;
|
use crate::thread::MessageId;
|
||||||
use crate::thread_store::SerializedMessage;
|
use crate::thread_store::SerializedMessage;
|
||||||
|
@ -200,8 +199,6 @@ impl ToolUseState {
|
||||||
) -> SharedString {
|
) -> SharedString {
|
||||||
if let Some(tool) = self.tools.tool(tool_name, cx) {
|
if let Some(tool) = self.tools.tool(tool_name, cx) {
|
||||||
tool.ui_text(input).into()
|
tool.ui_text(input).into()
|
||||||
} else if tool_name == ScriptingTool::NAME {
|
|
||||||
"Run Lua Script".into()
|
|
||||||
} else {
|
} else {
|
||||||
"Unknown tool".into()
|
"Unknown tool".into()
|
||||||
}
|
}
|
||||||
|
@ -285,7 +282,7 @@ impl ToolUseState {
|
||||||
ui_text: impl Into<Arc<str>>,
|
ui_text: impl Into<Arc<str>>,
|
||||||
input: serde_json::Value,
|
input: serde_json::Value,
|
||||||
messages: Arc<Vec<LanguageModelRequestMessage>>,
|
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) {
|
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
|
||||||
let ui_text = ui_text.into();
|
let ui_text = ui_text.into();
|
||||||
|
@ -294,7 +291,7 @@ impl ToolUseState {
|
||||||
tool_use_id,
|
tool_use_id,
|
||||||
input,
|
input,
|
||||||
messages,
|
messages,
|
||||||
tool_type,
|
tool,
|
||||||
ui_text,
|
ui_text,
|
||||||
};
|
};
|
||||||
tool_use.status = PendingToolUseStatus::NeedsConfirmation(Arc::new(confirmation));
|
tool_use.status = PendingToolUseStatus::NeedsConfirmation(Arc::new(confirmation));
|
||||||
|
@ -398,19 +395,13 @@ pub struct PendingToolUse {
|
||||||
pub status: PendingToolUseStatus,
|
pub status: PendingToolUseStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ToolType {
|
|
||||||
ScriptingTool,
|
|
||||||
NonScriptingTool(Arc<dyn Tool>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Confirmation {
|
pub struct Confirmation {
|
||||||
pub tool_use_id: LanguageModelToolUseId,
|
pub tool_use_id: LanguageModelToolUseId,
|
||||||
pub input: serde_json::Value,
|
pub input: serde_json::Value,
|
||||||
pub ui_text: Arc<str>,
|
pub ui_text: Arc<str>,
|
||||||
pub messages: Arc<Vec<LanguageModelRequestMessage>>,
|
pub messages: Arc<Vec<LanguageModelRequestMessage>>,
|
||||||
pub tool_type: ToolType,
|
pub tool: Arc<dyn Tool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -15,26 +15,14 @@ pub struct ToolWorkingSet {
|
||||||
state: Mutex<WorkingSetState>,
|
state: Mutex<WorkingSetState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct WorkingSetState {
|
struct WorkingSetState {
|
||||||
context_server_tools_by_id: HashMap<ToolId, Arc<dyn Tool>>,
|
context_server_tools_by_id: HashMap<ToolId, Arc<dyn Tool>>,
|
||||||
context_server_tools_by_name: HashMap<String, Arc<dyn Tool>>,
|
context_server_tools_by_name: HashMap<String, Arc<dyn Tool>>,
|
||||||
disabled_tools_by_source: HashMap<ToolSource, HashSet<Arc<str>>>,
|
disabled_tools_by_source: HashMap<ToolSource, HashSet<Arc<str>>>,
|
||||||
is_scripting_tool_disabled: bool,
|
|
||||||
next_tool_id: ToolId,
|
next_tool_id: ToolId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WorkingSetState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
context_server_tools_by_id: HashMap::default(),
|
|
||||||
context_server_tools_by_name: HashMap::default(),
|
|
||||||
disabled_tools_by_source: HashMap::default(),
|
|
||||||
is_scripting_tool_disabled: true,
|
|
||||||
next_tool_id: ToolId::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToolWorkingSet {
|
impl ToolWorkingSet {
|
||||||
pub fn tool(&self, name: &str, cx: &App) -> Option<Arc<dyn Tool>> {
|
pub fn tool(&self, name: &str, cx: &App) -> Option<Arc<dyn Tool>> {
|
||||||
self.state
|
self.state
|
||||||
|
@ -55,7 +43,7 @@ impl ToolWorkingSet {
|
||||||
|
|
||||||
pub fn are_all_tools_enabled(&self) -> bool {
|
pub fn are_all_tools_enabled(&self) -> bool {
|
||||||
let state = self.state.lock();
|
let state = self.state.lock();
|
||||||
state.disabled_tools_by_source.is_empty() && !state.is_scripting_tool_disabled
|
state.disabled_tools_by_source.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn are_all_tools_from_source_enabled(&self, source: &ToolSource) -> bool {
|
pub fn are_all_tools_from_source_enabled(&self, source: &ToolSource) -> bool {
|
||||||
|
@ -70,7 +58,6 @@ impl ToolWorkingSet {
|
||||||
pub fn enable_all_tools(&self) {
|
pub fn enable_all_tools(&self) {
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
state.disabled_tools_by_source.clear();
|
state.disabled_tools_by_source.clear();
|
||||||
state.enable_scripting_tool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_all_tools(&self, cx: &App) {
|
pub fn disable_all_tools(&self, cx: &App) {
|
||||||
|
@ -124,21 +111,6 @@ impl ToolWorkingSet {
|
||||||
.retain(|id, _| !tool_ids_to_remove.contains(id));
|
.retain(|id, _| !tool_ids_to_remove.contains(id));
|
||||||
state.tools_changed();
|
state.tools_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_scripting_tool_enabled(&self) -> bool {
|
|
||||||
let state = self.state.lock();
|
|
||||||
!state.is_scripting_tool_disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enable_scripting_tool(&self) {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
state.enable_scripting_tool();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable_scripting_tool(&self) {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
state.disable_scripting_tool();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkingSetState {
|
impl WorkingSetState {
|
||||||
|
@ -240,15 +212,5 @@ impl WorkingSetState {
|
||||||
|
|
||||||
self.disable(source, &tool_names);
|
self.disable(source, &tool_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.disable_scripting_tool();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_scripting_tool(&mut self) {
|
|
||||||
self.is_scripting_tool_disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disable_scripting_tool(&mut self) {
|
|
||||||
self.is_scripting_tool_disabled = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "scripting_tool"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition.workspace = true
|
|
||||||
publish.workspace = true
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/scripting_tool.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
buffer_diff.workspace = true
|
|
||||||
clock.workspace = true
|
|
||||||
collections.workspace = true
|
|
||||||
futures.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
language.workspace = true
|
|
||||||
log.workspace = true
|
|
||||||
mlua.workspace = true
|
|
||||||
parking_lot.workspace = true
|
|
||||||
project.workspace = true
|
|
||||||
regex.workspace = true
|
|
||||||
schemars.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
buffer_diff = { workspace = true, features = ["test-support"] }
|
|
||||||
clock = { workspace = true, features = ["test-support"] }
|
|
||||||
collections = { workspace = true, features = ["test-support"] }
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
language = { workspace = true, features = ["test-support"] }
|
|
||||||
project = { workspace = true, features = ["test-support"] }
|
|
||||||
rand.workspace = true
|
|
||||||
settings = { workspace = true, features = ["test-support"] }
|
|
|
@ -1 +0,0 @@
|
||||||
../../LICENSE-GPL
|
|
|
@ -1,55 +0,0 @@
|
||||||
---@diagnostic disable: undefined-global
|
|
||||||
|
|
||||||
-- Create a sandbox environment
|
|
||||||
local sandbox = {}
|
|
||||||
|
|
||||||
-- For now, add all globals to `sandbox` (so there effectively is no sandbox).
|
|
||||||
-- We still need the logic below so that we can do things like overriding print() to write
|
|
||||||
-- to our in-memory log rather than to stdout, we will delete this loop (and re-enable
|
|
||||||
-- the I/O module being sandboxed below) to have things be sandboxed again.
|
|
||||||
for k, v in pairs(_G) do
|
|
||||||
if sandbox[k] == nil then
|
|
||||||
sandbox[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Allow access to standard libraries (safe subset)
|
|
||||||
sandbox.string = string
|
|
||||||
sandbox.table = table
|
|
||||||
sandbox.math = math
|
|
||||||
sandbox.print = sb_print
|
|
||||||
sandbox.type = type
|
|
||||||
sandbox.tostring = tostring
|
|
||||||
sandbox.tonumber = tonumber
|
|
||||||
sandbox.pairs = pairs
|
|
||||||
sandbox.ipairs = ipairs
|
|
||||||
|
|
||||||
-- Access to custom functions
|
|
||||||
sandbox.search = search
|
|
||||||
sandbox.outline = outline
|
|
||||||
|
|
||||||
-- Create a sandboxed version of LuaFileIO
|
|
||||||
-- local io = {};
|
|
||||||
--
|
|
||||||
-- For now we are using unsandboxed io
|
|
||||||
local io = _G.io;
|
|
||||||
|
|
||||||
-- File functions
|
|
||||||
io.open = sb_io_open
|
|
||||||
|
|
||||||
-- Add the sandboxed io library to the sandbox environment
|
|
||||||
sandbox.io = io
|
|
||||||
|
|
||||||
-- Load the script with the sandbox environment
|
|
||||||
local user_script_fn, err = load(user_script, nil, "t", sandbox)
|
|
||||||
|
|
||||||
if not user_script_fn then
|
|
||||||
error("Failed to load user script: " .. tostring(err))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Execute the user script within the sandbox
|
|
||||||
local success, result = pcall(user_script_fn)
|
|
||||||
|
|
||||||
if not success then
|
|
||||||
error("Error executing user script: " .. tostring(result))
|
|
||||||
end
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,30 +0,0 @@
|
||||||
mod scripting_session;
|
|
||||||
|
|
||||||
pub use scripting_session::*;
|
|
||||||
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, JsonSchema)]
|
|
||||||
pub struct ScriptingToolInput {
|
|
||||||
pub lua_script: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ScriptingTool;
|
|
||||||
|
|
||||||
impl ScriptingTool {
|
|
||||||
pub const NAME: &str = "lua-interpreter";
|
|
||||||
|
|
||||||
pub const DESCRIPTION: &str = include_str!("scripting_tool_description.md");
|
|
||||||
|
|
||||||
pub fn input_schema() -> serde_json::Value {
|
|
||||||
let schema = schemars::schema_for!(ScriptingToolInput);
|
|
||||||
serde_json::to_value(&schema).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deserialize_input(
|
|
||||||
input: serde_json::Value,
|
|
||||||
) -> Result<ScriptingToolInput, serde_json::Error> {
|
|
||||||
serde_json::from_value(input)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
Evaluates the given Lua script in an interpreter with access to the Lua standard library. The tool returns the scripts output to stdout and any error that may have occurred.
|
|
||||||
|
|
||||||
Use this tool to explore the current project and edit the user's codebase or operating system as requested.
|
|
||||||
|
|
||||||
Additional functions provided:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
--- Search for matches of a regular expression in files.
|
|
||||||
-- @param pattern The regex pattern to search for (uses Rust's regex syntax)
|
|
||||||
-- @return An array of tables with 'path' (file path) and 'matches' (array of matching strings)
|
|
||||||
-- @usage local results = search("function\\s+\\w+")
|
|
||||||
function search(pattern)
|
|
||||||
-- Implementation provided by the tool
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generates an outline for the given file path, extracting top-level symbols such as functions, classes, exports, and other significant declarations. This provides a structural overview of the file's contents.
|
|
||||||
-- @param path
|
|
||||||
function outline(path)
|
|
||||||
-- Implementation provided by the tool
|
|
||||||
end
|
|
||||||
```
|
|
Loading…
Add table
Add a link
Reference in a new issue