1mod session;
2
3use project::Project;
4use session::*;
5
6use gpui::{App, AppContext as _, Entity, Task};
7use schemars::JsonSchema;
8use serde::Deserialize;
9
10#[derive(Debug, Deserialize, JsonSchema)]
11pub struct ScriptingToolInput {
12 pub lua_script: String,
13}
14
15pub struct ScriptingTool;
16
17impl ScriptingTool {
18 pub const NAME: &str = "lua-interpreter";
19
20 pub const DESCRIPTION: &str = include_str!("scripting_tool_description.txt");
21
22 pub fn input_schema() -> serde_json::Value {
23 let schema = schemars::schema_for!(ScriptingToolInput);
24 serde_json::to_value(&schema).unwrap()
25 }
26
27 pub fn run(
28 &self,
29 input: serde_json::Value,
30 project: Entity<Project>,
31 cx: &mut App,
32 ) -> Task<anyhow::Result<String>> {
33 let input = match serde_json::from_value::<ScriptingToolInput>(input) {
34 Err(err) => return Task::ready(Err(err.into())),
35 Ok(input) => input,
36 };
37
38 // TODO: Store a session per thread
39 let session = cx.new(|cx| ScriptingSession::new(project, cx));
40 let lua_script = input.lua_script;
41
42 let (script_id, script_task) =
43 session.update(cx, |session, cx| session.run_script(lua_script, cx));
44
45 cx.spawn(|cx| async move {
46 script_task.await;
47
48 let message = session.read_with(&cx, |session, _cx| {
49 // Using a id to get the script output seems impractical.
50 // Why not just include it in the Task result?
51 // This is because we'll later report the script state as it runs,
52 // currently not supported by the `Tool` interface.
53 session
54 .get(script_id)
55 .output_message_for_llm()
56 .expect("Script shouldn't still be running")
57 })?;
58
59 drop(session);
60 Ok(message)
61 })
62 }
63}